1
0
mirror of https://github.com/MarkParker5/STARK.git synced 2025-09-16 09:36:24 +02:00

Add online/offline mode, change Command.find() and @Command.background() returns, fix bugs

This commit is contained in:
dQz6tMwk8rJqvDR
2020-07-28 17:25:41 +03:00
parent 5e94014dcd
commit d75f1cb626
5 changed files with 68 additions and 37 deletions

View File

@@ -39,10 +39,10 @@ class Command(ABC):
} }
_regex = { _regex = {
# stars * # stars *
f'([A-Za-zА-ЯЁа-яё0-9]+)\*([A-Za-zА-ЯЁа-яё0-9]+)': r'\\b\1.*\2\\b', # 'te*xt' '([A-Za-zА-ЯЁа-яё0-9\(\)\[\]\{\}]+)\*([A-Za-zА-ЯЁа-яё0-9\(\)\[\]\{\}]+)': r'\\b\1.*\2\\b', # 'te*xt'
f'\*([A-Za-zА-ЯЁа-яё0-9]+)': r'\\b.*\1', # '*text' '\*([A-Za-zА-ЯЁа-яё0-9\(\)\[\]\{\}]+)': r'\\b.*\1', # '*text'
f'([A-Za-zА-ЯЁа-яё0-9]+)\*': r'\1.*\\b', # 'text*' '([A-Za-zА-ЯЁа-яё0-9\(\)\[\]\{\}]+)\*': r'\1.*\\b', # 'text*'
f'(^|\s)\*($|\s)': r'.*', # '*' ' * ' '(^|\s)\*($|\s)': r'.*', # '*' ' * '
# one of the list (a|b|c) # one of the list (a|b|c)
'\(((?:.*\|)*.*)\)': r'(?:\1)', '\(((?:.*\|)*.*)\)': r'(?:\1)',
# 0 or 1 the of list [a|b|c] # 0 or 1 the of list [a|b|c]
@@ -131,19 +131,24 @@ class Command(ABC):
list = Command.getList() list = Command.getList()
for i, obj in enumerate( list ): for i, obj in enumerate( list ):
chances[i] = 0 chances[i] = 0
x = 1 / ( sum([int(i) for i in obj.getKeywords().keys()]) or 1 ) k = 1 / ( sum( [int(w)*len(kw) for w, kw in obj.getKeywords().items()] ) or 1 )
for weight, kws in obj.getKeywords().items(): for weight, kws in obj.getKeywords().items():
k = x * weight / len(kws)
for kw in kws: for kw in kws:
chances[i] += Command.ratio(string, kw) * k chances[i] += Command.ratio(string, kw) * weight * k
if( sum( chances.values() ) ): if( sum( chances.values() ) ):
top = max( chances.values() ) / sum( chances.values() ) * 100 top = max( chances.values() ) / sum( chances.values() ) * 100
else: else:
return list[0] return {
'cmd': list[0],
'params': None,
}
#if( max( chances.values() ) < 800 or top < 80): return list[0] #if( max( chances.values() ) < 800 or top < 80): return list[0]
for i, chance in chances.items(): for i, chance in chances.items():
if chance == max( chances.values() ): if chance == max( chances.values() ):
return list[i] return {
'cmd': list[i],
'params': None,
}
@staticmethod @staticmethod
def reg_find(string): def reg_find(string):
@@ -155,15 +160,21 @@ class Command(ABC):
for ptrn, regex in Command._regex.items(): for ptrn, regex in Command._regex.items():
pattern = re.sub(re.compile(ptrn), regex, pattern) pattern = re.sub(re.compile(ptrn), regex, pattern)
# links $Pattern # links $Pattern
link = re.search(re.compile(f'\$[A-Za-zА-ЯЁа-яё0-9]+'), pattern) link = re.search(re.compile('\$[A-Za-zА-ЯЁа-яё0-9\(\)\[\]\{\}]+'), pattern)
if link: pattern = re.sub('\\'+link[0], f'(?P<{link[0][1:]}>{Command._patterns[link[0][1:]]})', pattern) if link: pattern = re.sub('\\'+link[0], f'(?P<{link[0][1:]}>{Command._patterns[link[0][1:]]})', pattern)
# find # find
match = re.search(re.compile(pattern), string) match = re.search(re.compile(pattern), string)
if(match): return obj # match.groupdict() if(match): return {
return None 'cmd': obj,
'params': match.groupdict(),
}
return {
'cmd': list[0],
'params': None,
}
@staticmethod @staticmethod
def background(answer = ''): def background(answer = '', voice = ''):
def decorator(cmd): def decorator(cmd):
def wrapper(text): def wrapper(text):
finish_event = Event() finish_event = Event()
@@ -172,6 +183,7 @@ class Command(ABC):
return { return {
'type': 'background', 'type': 'background',
'text': answer, 'text': answer,
'voice': voice,
'thread': { 'thread': {
'thread': thread, 'thread': thread,
'finish_event': finish_event, 'finish_event': finish_event,

View File

@@ -21,12 +21,12 @@ from .SmallTalk import *
import datetime, time import datetime, time
import math import math
from Command import Command from Command import Command
import time
################################################################################ ################################################################################
def method(text): def method(text):
return { return {
'type': 'simple', 'type': 'simple',
'text': 'Я не понимаю', 'text': 'Я не понимаю',
'voice': 'Я не понимаю',
} }
keywords = {} keywords = {}
@@ -96,11 +96,16 @@ def method(text):
str_num += 'десят' str_num += 'десят'
result.append(str_num) result.append(str_num)
return ' '.join(result) return ' '.join(result)
answer = f'Сейчас {get_str_num(hours, 0)} {str_hour}'
if(minutes): answer += f', {get_str_num(minutes, 1)} {str_minute}' voice = f'Сейчас {get_str_num(hours, 0)} {str_hour}'
if(minutes): voice += f', {get_str_num(minutes, 1)} {str_minute}'
hours = now.hour if now.hour > 9 else '0'+str(now.hour)
minutes = minutes if minutes > 9 else '0'+str(minutes) if minutes else '00'
text = f'Текущее время: {hours}:{minutes}'
return { return {
'type': 'simple', 'type': 'simple',
'text': answer 'text': text,
'voice': voice,
} }
keywords = { keywords = {
@@ -108,24 +113,25 @@ keywords = {
5: ['текущее', 'сейчас', 'время'], 5: ['текущее', 'сейчас', 'время'],
1: ['сколько'] 1: ['сколько']
} }
patterns = ['* который * час *', '* скольк* * врем* *', 'время'] patterns = ['* который * час *', '* скольк* * (врем|час)* *', '* врем* *']
ctime = SmallTalk('Current Time', keywords, patterns) ctime = SmallTalk('Current Time', keywords, patterns)
ctime.setStart(method) ctime.setStart(method)
################################################################################ ################################################################################
# Only for tests # Only for tests
@Command.background('Запускаю фоновый процесс') @Command.background(answer = 'Запуск фонового процесса', voice = 'Запускаю фоновый процесс')
def method(text, finish_event): def method(text, finish_event):
time.sleep(10) time.sleep(10)
finish_event.set() finish_event.set()
return { return {
'text': 'Фоновый процесс завершен', 'text': 'Фоновый процесс завершен',
'voice': 'Фоновый процесс завершен',
} }
keywords = { keywords = {
10: ['тестирование', 'проверка', 'потоков', 'фоновых', 'процессов'], 10: ['тестирование', 'проверка', 'потоков', 'фоновых', 'процессов'],
} }
patterns = ['* (тестир*|провер*) * [фоновых] * (процесс*|поток*) *'] patterns = ['* [тест|провер]* * [фонов*] * (процесс|поток)* *']
test = SmallTalk('Test threads', keywords, patterns) test = SmallTalk('Test threads', keywords, patterns)
test.setStart(method) test.setStart(method)
################################################################################ ################################################################################

View File

@@ -16,7 +16,6 @@ class Speech:
def speak(this): def speak(this):
if( os.path.exists(this._path) ): if( os.path.exists(this._path) ):
print(f'Говорю: {this._text}')
with open(this._path) as f: with open(this._path) as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as audio: with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as audio:
mixer.init() mixer.init()

View File

@@ -1,2 +1,3 @@
goole_tts_json_key = "tts-gc-key.json" goole_tts_json_key = "tts-gc-key.json"
language_code = "ru-RU" language_code = "ru-RU"
names = ['арчи', 'archie']

45
main.py
View File

@@ -2,11 +2,14 @@ import SpeechRecognition
import Text2Speech import Text2Speech
import SmallTalk import SmallTalk
from Command import Command from Command import Command
import config
listener = SpeechRecognition.SpeechToText() listener = SpeechRecognition.SpeechToText()
voice = Text2Speech.Engine() voice = Text2Speech.Engine()
threads = [] threads = []
memory = [] memory = []
online = False
voids = 0
listener.listen_noise() listener.listen_noise()
def check_threads(): def check_threads():
@@ -14,27 +17,37 @@ def check_threads():
if thread['finish_event'].is_set(): if thread['finish_event'].is_set():
responce = thread['thread'].join() responce = thread['thread'].join()
if responce['text']: if responce['text']:
voice.generate(responce['text']).speak() print(''+responce['text'])
if responce['voice']:
voice.generate(responce['voice']).speak()
thread['finish_event'].clear() thread['finish_event'].clear()
del thread del thread
while True: # main loop while True: # main loop
check_threads() check_threads()
print('Listening...') print('\nYou: ', end='')
speech = listener.listen() speech = listener.listen()
text = speech['text'] text = speech['text']
print('You: ') speech['status'] = 'ok' if text else 'void'
if text: if speech['status'] == 'ok':
cmd = Command.find(text) print(text)
responce = cmd.start(text) if set(config.names) & set(text.split(' ')): online = True
memory.insert(0, { if online:
'text': text, voids = 0
'cmd': cmd, cmd, params = Command.reg_find(text).values()
'responce': responce responce = cmd.start(text)
}) memory.insert(0, {
if responce['type'] == 'background': # add background thread to list 'text': text,
threads.append(responce['thread']) 'cmd': cmd,
if responce['text']: 'responce': responce
voice.generate(responce['text']).speak() })
if responce['type'] == 'background': # add background thread to list
threads.append(responce['thread'])
if responce['text']:
print('Archie: '+responce['text'])
if responce['voice']:
voice.generate(responce['voice']).speak()
else: else:
print(speech['status']) if speech['status'] == 'error': print('Отсутсвует подключение к интернету');
elif speech['status'] == 'void': voids += 1
if voids >= 3: online = False; voids = 0