You've already forked STARK
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:
@ -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()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
10
main.py
@ -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,
|
||||||
|
Reference in New Issue
Block a user