1
0
mirror of https://github.com/MarkParker5/STARK.git synced 2024-11-24 08:12:13 +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
#
# Command - parent of all command classes
# command - object (class instance)
# 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}
# 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.confirm() - Return True/False (User responce)
# this.keywords - dictionary of arrays keywords
@ -13,7 +16,16 @@
# (int)weight1 : ['word3', 'word4'],
# (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 fuzzywuzzy import fuzz
@ -55,10 +67,10 @@ class Command(ABC):
'\{((?:.*\|?)*?.*?)\}': r'(?:\1)+?',
}
def __init__(this, name, keywords = {}, patterns = [], subPatterns = []): # initialisation of new command
this._name = name
this._keywords = keywords
this._patterns = patterns
this._subPatterns = subPatterns
this._name = name
this._keywords = keywords
this._patterns = patterns
this._subPatterns = subPatterns
Command.append(this)
def __str__(this):
@ -67,8 +79,10 @@ class Command(ABC):
str += f'\t{key}:\t{value}\n'
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():
index = 0
for word in array:
@ -78,35 +92,39 @@ class Command(ABC):
return None # if not found
def removeKeyword(this, string):
position = this._getKeyword(string)
position = this.getKeyword(string)
if(position): del this._keywords[ position[0] ][ position[1] ]
def addKeyword(this, weight, string):
if this._getKeyword(string): return
def addKeyword(this, weight, string): # add new keywords to end of the list
if this.getKeyword(string): return
if( this._keywords.get(weight) ): this._keywords[weight].append(string)
else: this._keywords[weight] = [string]
def changeKeyword(this, weight, string):
this.removeKeyword(string)
this.addKeyword(weight, string)
def changeKeyword(this, weight, name): # set new weight to keyword (find by name)
this.removeKeyword(name)
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():
if match := re.search(re.compile(Command.compilePattern(pattern)), string):
return {
'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
def setConfirm(this, function): # define confirm (optional)
def setConfirm(this, function): # define confirm (optional)
this.confirm = function
# getters
######################################################################################
# GETTERS #
######################################################################################
def getName(this):
return this._name
@ -119,7 +137,9 @@ class Command(ABC):
def getSubPatterns(this):
return this._subPatterns
# abstract
######################################################################################
# ABSTRACT METHODS #
######################################################################################
@abstractmethod
def start(this, params): # main method
pass
@ -128,62 +148,53 @@ class Command(ABC):
def confirm(this): # optional method
pass
# static
######################################################################################
# STATIC METHODS #
######################################################################################
@staticmethod
def getList():
return Command._list
return Command._list # all commands
@staticmethod
def getRegexDict():
return Command._regex
return Command._regex # all standart patterns
@staticmethod
def getEntity(key):
entity = Command._entities.get(key)
#if type(entity) == 'function': entity = entity()
entity = Command._entities.get(key) # all linked $Pattern s
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
def append(obj):
def append(obj): # add new command to list
Command._list.append(obj)
@staticmethod
def getCommand(name):
def getCommand(name): # get command by name
for obj in Command.getList():
if obj.getName() == name: return obj
@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
return False
@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
@staticmethod
def compilePattern(pattern):
def compilePattern(pattern): # transform my syntax to standart regexp
# transform patterns to regexp
for ptrn, regex in Command.getRegexDict().items():
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)
if link: pattern = re.sub('\\'+link[0], f'(?P<{link[0][1:]}>{Command.getEntity( link[0][1:] )})', pattern)
# return compiled regexp
return pattern
@staticmethod
def find(string):
def find(string): # find command by fuzzywuzzy
string = string.lower()
chances = {}
list = Command.getList()
@ -212,7 +223,7 @@ class Command(ABC):
}
@staticmethod
def reg_find(string):
def reg_find(string): # find comman by pattern
string = string.lower()
list = Command.getList()
if not string: return {
@ -227,14 +238,14 @@ class Command(ABC):
'cmd': obj,
'params': {**match.groupdict(), 'string':string,},
}
# return QA-system if command not found
# return Question-Answer system if command not found
return {
'cmd': Command.QA,
'params': {'string':string,},
}
@staticmethod
def background(answer = '', voice = ''):
def background(answer = '', voice = ''): # make background cmd
def decorator(cmd): #wrapper of wrapper (decorator of decorator)
def wrapper(text):
finish_event = Event()

View File

@ -16,6 +16,8 @@
# 3. new_command = SmallTalk(Name, kw, patterns, subpatterns)
# 4. new_command.setStart(method)
# 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 time
import config
r = sr.Recognizer()
m = sr.Microphone(device_index=1)
m = sr.Microphone(device_index=config.device_index)
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.language = language
this.m = sr.Microphone(device_index = this.device)

View File

@ -1,7 +1,7 @@
from google.cloud import texttospeech
import os
from pygame import mixer
import time
from time import sleep
import mmap
import config
@ -22,7 +22,7 @@ class Speech:
mixer.music.load(audio)
mixer.music.play()
while mixer.music.get_busy():
time.sleep(0.1)
sleep(0.1)
if(not this._standart): os.remove(this._path)
@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"
device_index = 1
names = ['арчи', 'archie']

10
main.py
View File

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