Updated archtecture, fixed dependencies

This commit is contained in:
Nick Bifle 2023-04-16 12:51:26 +03:00
parent 5ed98994e9
commit 964d25de86
179 changed files with 609 additions and 1365 deletions

0
src/app/__init__.py Normal file
View file

165
src/app/commands.py Normal file
View file

@ -0,0 +1,165 @@
import os
import yaml
import time
import random
import openai
import config
import subprocess
from .tts import cached_response, model_response
from pycaw.pycaw import (
AudioUtilities,
IAudioEndpointVolume
)
from ctypes import POINTER, cast
from comtypes import CLSCTX_ALL
from gpytranslate import SyncTranslator
RESPONSES = yaml.safe_load(
open('responses.yaml'),
)
CDIR = os.getcwd()
t = SyncTranslator()
openai.api_key = config.OPENAI_TOKEN
def execute_cmd(cmd: str):
if cmd == 'help':
text = (
"Я умею: ..."
"произносить время ..."
"рассказывать анекдоты ..."
"и открывать браузер"
)
model_response(text)
elif cmd == 'joke':
jokes = ['Как смеются программисты? ... ехе ехе ехе',
'ЭсКьюЭль запрос заходит в бар, подходит к двум столам и спрашивает .. «м+ожно присоединиться?»',
'Программист это машина для преобразования кофе в код']
cached_response("ok")
model_response(random.choice(jokes))
elif cmd == 'open_browser':
subprocess.Popen([f'{CDIR}\\custom-commands\\Run browser.exe'])
cached_response("ok")
elif cmd == 'open_youtube':
subprocess.Popen([f'{CDIR}\\custom-commands\\Run youtube.exe'])
cached_response("ok")
elif cmd == 'open_google':
subprocess.Popen([f'{CDIR}\\custom-commands\\Run google.exe'])
cached_response("ok")
elif cmd == 'music':
subprocess.Popen([f'{CDIR}\\custom-commands\\Run music.exe'])
cached_response("ok")
elif cmd == 'music_off':
subprocess.Popen([f'{CDIR}\\custom-commands\\Stop music.exe'])
time.sleep(0.2)
cached_response("ok")
elif cmd == 'music_save':
subprocess.Popen([f'{CDIR}\\custom-commands\\Save music.exe'])
time.sleep(0.2)
cached_response("ok")
elif cmd == 'music_next':
subprocess.Popen([f'{CDIR}\\custom-commands\\Next music.exe'])
time.sleep(0.2)
cached_response("ok")
elif cmd == 'music_prev':
subprocess.Popen([f'{CDIR}\\custom-commands\\Prev music.exe'])
time.sleep(0.2)
cached_response("ok")
elif cmd == 'sound_off':
cached_response("ok")
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
volume.SetMute(1, None)
elif cmd == 'sound_on':
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
volume.SetMute(0, None)
cached_response("ok")
elif cmd == 'thanks':
cached_response("thanks")
elif cmd == 'stupid':
cached_response("stupid")
elif cmd == 'gaming_mode_on':
cached_response("ok")
subprocess.check_call([f'{CDIR}\\custom-commands\\Switch to gaming mode.exe'])
cached_response("ready")
elif cmd == 'gaming_mode_off':
cached_response("ok")
subprocess.check_call([f'{CDIR}\\custom-commands\\Switch back to workspace.exe'])
cached_response("ready")
elif cmd == 'switch_to_headphones':
cached_response("ok")
subprocess.check_call([f'{CDIR}\\custom-commands\\Switch to headphones.exe'])
time.sleep(0.5)
cached_response("ready")
elif cmd == 'switch_to_dynamics':
cached_response("ok")
subprocess.check_call([f'{CDIR}\\custom-commands\\Switch to dynamics.exe'])
time.sleep(0.5)
cached_response("ready")
elif cmd == 'off':
cached_response("off")
exit(0)
def gpt_answer(message):
model_engine = "text-davinci-003"
max_tokens = 128 # default 1024
prompt = t.translate(message, targetlang="en")
completion = openai.Completion.create(
engine=model_engine,
prompt=prompt.text,
max_tokens=max_tokens,
temperature=0.5,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
translated_result = t.translate(completion.choices[0].text, targetlang="ru")
return translated_result.text

32
src/app/recorder.py Normal file
View file

@ -0,0 +1,32 @@
import logging
from queue import Queue
from sounddevice import RawInputStream
log = logging.getLogger('app.recorder')
class Recorder(object):
def __init__(self, device: int, sample_rate: int=16_000):
self.queue = Queue()
self.stream = RawInputStream(
samplerate=sample_rate,
blocksize=8_000,
device=device,
dtype='int16',
channels=1,
callback=self._write_to_queue,
)
def _write_to_queue(self, data, _, __, status):
if status:
log.error(str(status))
self.queue.put(bytes(data))
def __call__(self):
return self.stream

139
src/app/stt.py Normal file
View file

@ -0,0 +1,139 @@
import json
import time
import yaml
import config
import logging
from .tts import cached_response, model_response
from .commands import gpt_answer
from .recorder import Recorder
from fuzzywuzzy import fuzz
from vosk import KaldiRecognizer
log = logging.getLogger('jarvis.stt')
COMMANDS = yaml.safe_load(open('responses.yaml'))
class Dispatcher(object):
_last_action = 0
def __init__(self, recorder: Recorder, vosk: KaldiRecognizer):
self.recorder = recorder
self.vosk = vosk
def start(self):
log.info('Started recording')
with self.recorder():
while True:
data = self.recorder.queue.get()
if not self.vosk.AcceptWaveform(data):
continue
text = json.loads(self.vosk.Result())['text']
if self._last_action < time.time() - 10:
self.check_input(text)
else:
self.dispatch(text)
def check_input(self, text: str):
if not text:
return
for word in text.split():
if fuzz.ratio(word, 'джарвис') >= 60:
cached_response('ok')
self._last_action = time.time()
return self.dispatch(text)
def dispatch(self, text: str):
if text and self.va_respond(text):
self._last_action = time.time()
def va_respond(self, voice: str):
log.info('Распознано: ')
cmd = self.recognize_cmd(voice)
if len(cmd['cmd'].strip()) <= 0:
return False
elif cmd['percent'] < 70 or cmd['cmd'] not in config.VA_CMD_LIST.keys():
if fuzz.ratio(voice.join(voice.split()[:1]).strip(), "скажи") > 75:
gpt_result = gpt_answer(voice)
model_response(gpt_result)
return False
else:
cached_response("not_found")
return False
else:
self.execute_cmd()
return True
def respond(self, phrase: str):
self.recorder.stream.stop()
cached_response(phrase)
self.recorder.stream.stop()
@staticmethod
def filter_cmd(raw_voice: str):
cmd = raw_voice
for x in config.VA_ALIAS:
cmd = cmd.replace(x, "").strip()
for x in config.VA_TBR:
cmd = cmd.replace(x, "").strip()
return cmd
@classmethod
def recognize_cmd(cls, cmd: str):
cmd = cls.filter_cmd(cmd)
rc = {'cmd': '', 'percent': 0}
for c, v in COMMANDS.items():
for x in v:
vrt = fuzz.ratio(cmd, x)
if vrt > rc['percent']:
rc['cmd'] = c
rc['percent'] = vrt
return rc

60
src/app/tts.py Normal file
View file

@ -0,0 +1,60 @@
import os
import re
import torch
import random
import sounddevice
from pydub import AudioSegment, playback
device = torch.device('cpu')
model, _ = torch.hub.load(
repo_or_dir='snakers4/silero-models',
model='silero_tts',
language='ru',
speaker='ru_v3',
)
model.to(device)
def from_wav(path: str) -> None:
"""
Play an audiofile
:param str path: File path
"""
with open(path, 'rb') as file:
audio = AudioSegment.from_wav(file)
playback.play(audio)
def cached_response(keyword: str, basedir: str='src', ext: str='wav') -> None:
files = os.listdir(basedir)
regexp = re.compile(
r'%s\d{0,}\.%s' % (
keyword, ext,
),
)
filename = random.choice([
filename for filename in files
if re.match(regexp, filename)
])
return from_wav(
os.path.join(basedir, filename),
)
def model_response(text: str):
audio: torch.Tensor = model.apply_tts(
text=text + "..",
speaker='aidar',
sample_rate=24000,
put_accent=True,
put_yo=True,
)
sounddevice.play(audio, 24000, blocking=True)

13
src/config.py Normal file
View file

@ -0,0 +1,13 @@
VA_NAME = 'Jarvis'
VA_VER = "3.0"
VA_ALIAS = ('джарвис', 'кеша', 'кеш', 'инокентий', 'иннокентий', 'кишун', 'киш', 'кишаня', 'кешечка', 'кэш', 'кэша')
VA_TBR = ('скажи', 'покажи', 'ответь', 'произнеси', 'расскажи', 'сколько')
MICROPHONE_INDEX = 0 # ID микрофона (можете просто менять ID пока при запуске не отобразится нужный)
CHROME_PATH = 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s'
OPENAI_TOKEN = "<ТУТ ТОКЕН CHAT-GPT>"

View file

@ -0,0 +1,19 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Process, Exist, Y.Music.exe
If ErrorLevel = 0
{
; APP IS NOT RUNNING
}
Else
{
; APP IS RUNNING
;MsgBox, Already running
Run C:\Users\Abraham\Documents\WinStoreApps\YandexMusic
sleep 100
Send, {Ctrl down}f{Ctrl up}
}
Return

Binary file not shown.

View file

@ -0,0 +1,19 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Process, Exist, Y.Music.exe
If ErrorLevel = 0
{
; APP IS NOT RUNNING
}
Else
{
; APP IS RUNNING
;MsgBox, Already running
Run C:\Users\Abraham\Documents\WinStoreApps\YandexMusic
sleep 100
Send, {Ctrl down}b{Ctrl up}
}
Return

Binary file not shown.

View file

@ -0,0 +1,6 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Run C:/Program Files (x86)/Google/Chrome/Application/chrome.exe

Binary file not shown.

View file

@ -0,0 +1,6 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Run C:/Program Files (x86)/Google/Chrome/Application/chrome.exe "https://google.com"

Binary file not shown.

View file

@ -0,0 +1,41 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Process, Exist, Y.Music.exe
If ErrorLevel = 0
{
; APP IS NOT RUNNING
; Run https://music.yandex.ru/home
Run C:\Users\Abraham\Documents\WinStoreApps\YandexMusic
; Autoplay
sleep 3000
Send, {Ctrl down}p{Ctrl up}
sleep 10
; Open full
Loop, 4
{
Send, {Tab}
sleep 10
}
Send, {Enter}
sleep 1500
Loop, 7
{
Send, {Down}
sleep 50
}
sleep 1000
Send, {Enter}
}
Else
{
; APP IS RUNNING
;MsgBox, Already running
}
Return

Binary file not shown.

View file

@ -0,0 +1,6 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Run C:/Program Files (x86)/Google/Chrome/Application/chrome.exe "https://youtube.com"

Binary file not shown.

View file

@ -0,0 +1,19 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Process, Exist, Y.Music.exe
If ErrorLevel = 0
{
; APP IS NOT RUNNING
}
Else
{
; APP IS RUNNING
;MsgBox, Already running
Run C:\Users\Abraham\Documents\WinStoreApps\YandexMusic
sleep 100
Send, {Ctrl down}l{Ctrl up}
}
Return

Binary file not shown.

View file

@ -0,0 +1,6 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Process, Close, Y.Music.exe

Binary file not shown.

View file

@ -0,0 +1,16 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; Step 1. Close steam.
WinKill, AHK_exe Steam.exe
Process, Close, Steam.exe
; Step 2. Switch monitor profile.
RunWait C:\MonitorProfileSwitcher\MonitorSwitcher.exe -load:"C:\Users\Abraham\AppData\Roaming\MonitorSwitcher\Profiles\Workspace.xml"
Sleep, 7000
; Step 3. Switch audio device to Luna Edifier.
Run, nircmd setdefaultsounddevice "Luna Edifier" 1

Binary file not shown.

View file

@ -0,0 +1,6 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Run, nircmd setdefaultsounddevice "Luna Edifier" 1

Binary file not shown.

View file

@ -0,0 +1,19 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; Step 1. Close steam.
WinKill, AHK_exe Steam.exe
Process, Close, Steam.exe
; Step 2. Switch monitor profile.
RunWait C:\MonitorProfileSwitcher\MonitorSwitcher.exe -load:"C:\Users\Abraham\AppData\Roaming\MonitorSwitcher\Profiles\Gaming.xml"
Sleep, 7000
; Step 3. Switch audio device to LG TV.
Run, nircmd setdefaultsounddevice "LG TV" 1
; Step 4. Run Steam big picture.
Run, steam://open/bigpicture

Binary file not shown.

View file

@ -0,0 +1,6 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Run, nircmd setdefaultsounddevice "Razer Kraken" 1

Binary file not shown.

Binary file not shown.

32
src/main.py Normal file
View file

@ -0,0 +1,32 @@
import logging
from app import tts
from app.stt import Dispatcher
from app.recorder import Recorder
from vosk import KaldiRecognizer, Model, SetLogLevel
log = logging.getLogger('jarvis.main')
def main():
log.info('Starting up...')
tts.cached_response('run')
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
SetLogLevel(-1)
vosk = KaldiRecognizer(Model("model_small"), 16000)
recorder = Recorder(9)
dp = Dispatcher(recorder, vosk)
dp.start()
if __name__ == '__main__':
main()

11
src/requirements.txt Normal file
View file

@ -0,0 +1,11 @@
pvporcupine == 2.2.0
sounddevice == 0.4.6
pydub == 0.25.1
pycaw == 20230407
pyyaml == 6.0
python-levenshtein == 0.20.9
vosk == 0.3.45
torch == 2.0.0
omegaconf == 2.3.0
gpytranslate == 1.5.1
openai == 0.27.4

157
src/responses.yaml Normal file
View file

@ -0,0 +1,157 @@
gaming_mode_off:
- рабочий режим
- вернись в рабочий режим
- переключись на компьютер
- обратно на компьютер
- отключи игровой режим
- выйди из игрового режима
- вернись на компьютер
- выход с игрового режима
- рабочее пространство
- вернись в игровой режим
- выключи игровой режим
gaming_mode_on:
- включи игровой режим
- перейди в игровой режим
- я хочу поиграть
- переключись на телевизор
music:
- давай музыку
- музыка
- яндекс музыка
- включи музыку
- открой музыку
- послушаем музыку
- хочу музыку
- врубай музло
- включи что-то послушать
- давай что-то послушаем
music_next:
- следующий трек
- следующая мелодия
- следующая песня
- переключи трек
- переключи музыку
- переключи мелодию
- переключи песню
- следующая музыка
music_off:
- выключи музыку
- отруби музыку
- убери музыку
- отключи музыку
- закрой музыку
- останови музыку
- хватит музыки
music_prev:
- предыдущая музыка
- предыдущий трек
- предыдущая мелодия
- предыдущая песня
- верни трек
- верни мелодию
- верни песню
- верни прошлый трек
- верни прошлую мелодию
- верни прошлую песню
- верни прошлую музыку
- верни то что играло
- давай предыдущий трек
- переключи музыку обратно
- переключи на прошлый трек
- переключи на прошлую мелодию
- переключи на прошлую песню
music_save:
- сохрани трек
- мне нравится трек
- сохрани песню
- мне нравится песня
- добавь трек в избранное
- добавь песню в избранное
- запомни мелодию
- запомни трек
- запомни песню
- добавь мелодию в избранное
- сохрани то что сейчас играет
- добавь то что сейчас играет в избранное
- лайкни трек
- лайкни мелодию
- лайкни песню
'off':
- выключись
- вырубись
- завершить работу
- закройся
- отключись
- заверши свою работу
- на сегодня хватит
- выгрузи себя из памяти
- ты мне надоел
- пора спать
open_browser:
- открой браузер
- запусти браузер
- открой гугл хром
- гугл хром
open_google:
- открой гугл
- гугл
- запусти гугл
open_youtube:
- открой ютуб
- ютуб
- запусти ютуб
sound_off:
- выключи звук
- беззвучный режим
- режим без звука
- отключи звук
sound_on:
- включи звук
- режим со звуком
- верни звук
stupid:
- ты дурак
- ты дебил
- ты глупый
- ты тупой
switch_to_dynamics:
- переключи на динамики
- включи динамики
- перейди на динамики
- давай звук в динамики
- давай звук на динамики
- переключи звук в динамики
- переключи звук на динамики
- переключи на колонки
- включи колонки
- перейди на колонки
- давай звук в колонки
- давай звук на колонки
- переключи звук в колонки
- переключи звук на колонки
switch_to_headphones:
- переключи на наушники
- включи наушники
- перейди на наушники
- давай звук в наушники
- давай звук на наушники
- переключи звук в наушники
- переключи звук на наушники
- переключи на кракены
- включи кракены
- перейди на кракены
- давай звук в кракены
- давай звук на кракены
- переключи звук в кракены
- переключи звук на кракены
thanks:
- спасибо
- молодец
- респект
- ты супер
- отличная работа
- ты крут
- ты большой молодец
- ты реально крут
- ты афигенный

BIN
src/src/greet1.wav Normal file

Binary file not shown.

BIN
src/src/greet2.wav Normal file

Binary file not shown.

BIN
src/src/greet3.wav Normal file

Binary file not shown.

BIN
src/src/not_found.wav Normal file

Binary file not shown.

BIN
src/src/off.wav Normal file

Binary file not shown.

BIN
src/src/ok1.wav Normal file

Binary file not shown.

BIN
src/src/ok2.wav Normal file

Binary file not shown.

BIN
src/src/ok3.wav Normal file

Binary file not shown.

BIN
src/src/ready.wav Normal file

Binary file not shown.

BIN
src/src/run.wav Normal file

Binary file not shown.

BIN
src/src/stupid.wav Normal file

Binary file not shown.

BIN
src/src/thanks.wav Normal file

Binary file not shown.