1
0
mirror of https://github.com/MarkParker5/STARK.git synced 2025-07-12 22:50:22 +02:00

comments, small changes

This commit is contained in:
MarkParker5
2020-08-29 19:58:39 +03:00
parent d9284a560f
commit 825ee4c865
6 changed files with 72 additions and 58 deletions

View File

@ -1,10 +1,13 @@
# Abstract class Command # Abstract class Command
#
# Command - parent of all command classes # Command - parent of all command classes
# command - object (class instance) # command - object (class instance)
# Command.list - list of all commands # Command.list - list of all commands
# Command.find() - recognize command from a string, return command object # Command.find() - recognize command from a string by fuzzywuzzy, return command object
# must return dict like {'cmd': cmd, 'params': params} # must return dict like {'cmd': cmd, 'params': params}
# this - object (class instance) pointer # Command.reg_find() - recognize command from a string with regexe patterns, return command object
# must return dict like {'cmd': cmd, 'params': params}
# this - object (class instance) pointer (self)
# abstract this.start() - required method for all commands # abstract this.start() - required method for all commands
# abstract this.confirm() - Return True/False (User responce) # abstract this.confirm() - Return True/False (User responce)
# this.keywords - dictionary of arrays keywords # this.keywords - dictionary of arrays keywords
@ -13,7 +16,16 @@
# (int)weight1 : ['word3', 'word4'], # (int)weight1 : ['word3', 'word4'],
# (int)weight2 : ['word5', 'word6', 'word7', 'word8', 'word9'], # (int)weight2 : ['word5', 'word6', 'word7', 'word8', 'word9'],
# } # }
# this.patterns - list of command patterns
# this.subpatterns - list of subpaterns (context patterns)
# like ['* который * час *', '* скольк* * (врем|час)* *']
# Command._entities - linked patterns $Pattern
# Command.regex - regex patterns dict for better syntax
# #
#
#
from abc import ABC, abstractmethod # for abstract class and methods from abc import ABC, abstractmethod # for abstract class and methods
from fuzzywuzzy import fuzz from fuzzywuzzy import fuzz
@ -55,10 +67,10 @@ class Command(ABC):
'\{((?:.*\|?)*?.*?)\}': r'(?:\1)+?', '\{((?:.*\|?)*?.*?)\}': r'(?:\1)+?',
} }
def __init__(this, name, keywords = {}, patterns = [], subPatterns = []): # initialisation of new command def __init__(this, name, keywords = {}, patterns = [], subPatterns = []): # initialisation of new command
this._name = name this._name = name
this._keywords = keywords this._keywords = keywords
this._patterns = patterns this._patterns = patterns
this._subPatterns = subPatterns this._subPatterns = subPatterns
Command.append(this) Command.append(this)
def __str__(this): def __str__(this):
@ -67,8 +79,10 @@ class Command(ABC):
str += f'\t{key}:\t{value}\n' str += f'\t{key}:\t{value}\n'
return str return str
# control keywords ######################################################################################
def _getKeyword(this, string): # return position of keyword # CONTROL KEYWORDS #
######################################################################################
def getKeyword(this, string): # return position of the keyword
for weight, array in this._keywords.items(): for weight, array in this._keywords.items():
index = 0 index = 0
for word in array: for word in array:
@ -78,35 +92,39 @@ class Command(ABC):
return None # if not found return None # if not found
def removeKeyword(this, string): def removeKeyword(this, string):
position = this._getKeyword(string) position = this.getKeyword(string)
if(position): del this._keywords[ position[0] ][ position[1] ] if(position): del this._keywords[ position[0] ][ position[1] ]
def addKeyword(this, weight, string): def addKeyword(this, weight, string): # add new keywords to end of the list
if this._getKeyword(string): return if this.getKeyword(string): return
if( this._keywords.get(weight) ): this._keywords[weight].append(string) if( this._keywords.get(weight) ): this._keywords[weight].append(string)
else: this._keywords[weight] = [string] else: this._keywords[weight] = [string]
def changeKeyword(this, weight, string): def changeKeyword(this, weight, name): # set new weight to keyword (find by name)
this.removeKeyword(string) this.removeKeyword(name)
this.addKeyword(weight, string) this.addKeyword(weight, name)
def checkContext(this, string): def checkContext(this, string): # return cmd if the string matches the cmd context
for pattern in this.getSubPatterns(): for pattern in this.getSubPatterns():
if match := re.search(re.compile(Command.compilePattern(pattern)), string): if match := re.search(re.compile(Command.compilePattern(pattern)), string):
return { return {
'cmd': this, 'cmd': this,
'params': {**match.groupdict(), 'string':string}, 'params': {**match.groupdict(), 'string':string}, # return parans+initial text
} }
raise Exception("Not Found") raise Exception("Not Found") # raise exception if context not found
# setters ######################################################################################
def setStart(this, function): # define start (required) # SETTERS #
######################################################################################
def setStart(this, function): # define start (required)
this.start = function this.start = function
def setConfirm(this, function): # define confirm (optional) def setConfirm(this, function): # define confirm (optional)
this.confirm = function this.confirm = function
# getters ######################################################################################
# GETTERS #
######################################################################################
def getName(this): def getName(this):
return this._name return this._name
@ -119,7 +137,9 @@ class Command(ABC):
def getSubPatterns(this): def getSubPatterns(this):
return this._subPatterns return this._subPatterns
# abstract ######################################################################################
# ABSTRACT METHODS #
######################################################################################
@abstractmethod @abstractmethod
def start(this, params): # main method def start(this, params): # main method
pass pass
@ -128,62 +148,53 @@ class Command(ABC):
def confirm(this): # optional method def confirm(this): # optional method
pass pass
# static ######################################################################################
# STATIC METHODS #
######################################################################################
@staticmethod @staticmethod
def getList(): def getList():
return Command._list return Command._list # all commands
@staticmethod @staticmethod
def getRegexDict(): def getRegexDict():
return Command._regex return Command._regex # all standart patterns
@staticmethod @staticmethod
def getEntity(key): def getEntity(key):
entity = Command._entities.get(key) entity = Command._entities.get(key) # all linked $Pattern s
#if type(entity) == 'function': entity = entity()
return entity() return entity()
# @staticmethod
# def getEntities():
# return {
# 'word': r'\b[A-Za-zА-ЯЁа-яё0-9\-]+\b',
# 'text': r'[A-Za-zА-ЯЁа-яё0-9\- ]+',
# 'quest' : Command.compilePattern('(кто|что|как|какой|какая|какое|где|зачем|почему|сколько|чей|куда|когда)'),
# 'repeat': Command.compilePattern('* ((повтор*)|(еще раз)|(еще*раз)*) *'),
# }
# # return Command._entities
@staticmethod @staticmethod
def append(obj): def append(obj): # add new command to list
Command._list.append(obj) Command._list.append(obj)
@staticmethod @staticmethod
def getCommand(name): def getCommand(name): # get command by name
for obj in Command.getList(): for obj in Command.getList():
if obj.getName() == name: return obj if obj.getName() == name: return obj
@staticmethod @staticmethod
def isRepeat(string): def isRepeat(string): # return True if command is repeat-cmd
if re.search(re.compile(Command.getEntity('repeat')), string): return True if re.search(re.compile(Command.getEntity('repeat')), string): return True
return False return False
@staticmethod @staticmethod
def ratio(string, word): def ratio(string, word): # get average distance of string and pattern
return ( fuzz.WRatio(string, word) + fuzz.ratio(string, word) ) / 2 return ( fuzz.WRatio(string, word) + fuzz.ratio(string, word) ) / 2
@staticmethod @staticmethod
def compilePattern(pattern): def compilePattern(pattern): # transform my syntax to standart regexp
# transform patterns to regexp # transform patterns to regexp
for ptrn, regex in Command.getRegexDict().items(): for ptrn, regex in Command.getRegexDict().items():
pattern = re.sub(re.compile(ptrn), regex, pattern) pattern = re.sub(re.compile(ptrn), regex, pattern)
# find links like $Pattern # find and replace links like $Pattern
link = re.search(re.compile('\$[a-z]+'), pattern) link = re.search(re.compile('\$[a-z]+'), pattern)
if link: pattern = re.sub('\\'+link[0], f'(?P<{link[0][1:]}>{Command.getEntity( link[0][1:] )})', pattern) if link: pattern = re.sub('\\'+link[0], f'(?P<{link[0][1:]}>{Command.getEntity( link[0][1:] )})', pattern)
# return compiled regexp # return compiled regexp
return pattern return pattern
@staticmethod @staticmethod
def find(string): def find(string): # find command by fuzzywuzzy
string = string.lower() string = string.lower()
chances = {} chances = {}
list = Command.getList() list = Command.getList()
@ -212,7 +223,7 @@ class Command(ABC):
} }
@staticmethod @staticmethod
def reg_find(string): def reg_find(string): # find comman by pattern
string = string.lower() string = string.lower()
list = Command.getList() list = Command.getList()
if not string: return { if not string: return {
@ -227,14 +238,14 @@ class Command(ABC):
'cmd': obj, 'cmd': obj,
'params': {**match.groupdict(), 'string':string,}, 'params': {**match.groupdict(), 'string':string,},
} }
# return QA-system if command not found # return Question-Answer system if command not found
return { return {
'cmd': Command.QA, 'cmd': Command.QA,
'params': {'string':string,}, 'params': {'string':string,},
} }
@staticmethod @staticmethod
def background(answer = '', voice = ''): def background(answer = '', voice = ''): # make background cmd
def decorator(cmd): #wrapper of wrapper (decorator of decorator) def decorator(cmd): #wrapper of wrapper (decorator of decorator)
def wrapper(text): def wrapper(text):
finish_event = Event() finish_event = Event()

View File

@ -16,6 +16,8 @@
# 3. new_command = SmallTalk(Name, kw, patterns, subpatterns) # 3. new_command = SmallTalk(Name, kw, patterns, subpatterns)
# 4. new_command.setStart(method) # 4. new_command.setStart(method)
# 5. new_command.setConfirm(confirm_method) # optional, not required # 5. new_command.setConfirm(confirm_method) # optional, not required
#
# @background(voice_to_speak, text_for_print) for background methods

View File

@ -1,11 +1,11 @@
import speech_recognition as sr import speech_recognition as sr
import time import config
r = sr.Recognizer() r = sr.Recognizer()
m = sr.Microphone(device_index=1) m = sr.Microphone(device_index=config.device_index)
class SpeechToText: class SpeechToText:
def __init__(this, device = 1, language = "ru-RU", pause_threshold = 0.5): def __init__(this, device = config.device_index, language = config.language_code, pause_threshold = 0.5):
this.device = 1 this.device = 1
this.language = language this.language = language
this.m = sr.Microphone(device_index = this.device) this.m = sr.Microphone(device_index = this.device)

View File

@ -1,7 +1,7 @@
from google.cloud import texttospeech from google.cloud import texttospeech
import os import os
from pygame import mixer from pygame import mixer
import time from time import sleep
import mmap import mmap
import config import config
@ -22,7 +22,7 @@ class Speech:
mixer.music.load(audio) mixer.music.load(audio)
mixer.music.play() mixer.music.play()
while mixer.music.get_busy(): while mixer.music.get_busy():
time.sleep(0.1) sleep(0.1)
if(not this._standart): os.remove(this._path) if(not this._standart): os.remove(this._path)
@staticmethod @staticmethod

View File

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

10
main.py
View File

@ -14,10 +14,12 @@ voids = 0
listener.listen_noise() listener.listen_noise()
def reply(responce): def reply(responce):
if responce['text']: if responce['text']: # print answer
print('Archie: '+responce['text']) print('Archie: '+responce['text'])
if responce['voice']: if responce['voice']: # say answer
voice.generate(responce['voice']).speak() voice.generate(responce['voice']).speak()
if responce['type'] == 'background': # add background thread to list
threads.append(responce['thread'])
def check_threads(): def check_threads():
for thread in threads: for thread in threads:
@ -37,7 +39,7 @@ while True: # main loop
voids = 0 voids = 0
if name := list(set(config.names) & set(text.split(' '))): if name := list(set(config.names) & set(text.split(' '))):
online = True online = True
text = text.replace(name[0], '').strip() text = text.replace(name[0], '').strip()
if online: if online:
if Command.isRepeat(text): if Command.isRepeat(text):
reply(memory[0]['responce']); reply(memory[0]['responce']);
@ -46,8 +48,6 @@ while True: # main loop
except: cmd, params = Command.reg_find(text).values() except: cmd, params = Command.reg_find(text).values()
responce = cmd.start(params) responce = cmd.start(params)
reply(responce) reply(responce)
if responce['type'] == 'background': # add background thread to list
threads.append(responce['thread'])
memory.insert(0, { memory.insert(0, {
'text': text, 'text': text,
'cmd': cmd, 'cmd': cmd,