Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f2f9955d6 | |||
| 92a8d35e15 | |||
| daf7211394 | |||
| ee5acf4316 | |||
| 36391ba187 | |||
| aa1e424e8b | |||
| 789f4f38d5 | |||
| e6c7006f1f | |||
| 9d08a7eb85 | |||
| 49946322bb |
@@ -0,0 +1,13 @@
|
||||
VA_ALIAS='("джарвис",)'
|
||||
VOSK_MODEL_NAME='vosk-model-small-ru-0.22' # vosk-model-ru-0.42
|
||||
MICROPHONE_INDEX=-1
|
||||
PICOVOICE_TOKEN='token'
|
||||
|
||||
|
||||
# home assistant
|
||||
HOME_ASSISTANT_URL='http://localhost:8123/api'
|
||||
HOME_ASSISTANT_TOKEN=''
|
||||
|
||||
# weather
|
||||
WEATHER_DEFAULT_CITY='krasnoyarsk'
|
||||
WEATHER_URL='https://yandex.ru/pogoda'
|
||||
@@ -46,6 +46,7 @@ music_on:
|
||||
- хочу послушать музыку
|
||||
- запусти плейлист
|
||||
music_off:
|
||||
- пауза
|
||||
- выключи музыку
|
||||
- остановить музыку
|
||||
- пауза музыки
|
||||
@@ -72,6 +73,7 @@ weather:
|
||||
- возможен дождь сегодня?
|
||||
- прогноз погоды на сегодня
|
||||
- погода
|
||||
- скажи погоду
|
||||
home_assistant_execute:
|
||||
- включи телевизор
|
||||
- выключи телевизор
|
||||
|
||||
+15
-7
@@ -1,10 +1,18 @@
|
||||
VA_ALIAS = ("джарвис",)
|
||||
VA_TBR = ("скажи", "покажи", "ответь", "произнеси", "расскажи", "сколько", "слушай")
|
||||
MODEL_NAME = "vosk-model-small-ru-0.22" # vosk-model-ru-0.42
|
||||
MICROPHONE_INDEX = -1
|
||||
PICOVOICE_TOKEN = "4xbwaZwZmSHeTiowFl5Rgqsc8CR4FKGV8YueJUlR4Zt2e1kB64IDcA=="
|
||||
import environs
|
||||
import ast
|
||||
|
||||
env = environs.Env()
|
||||
env.read_env()
|
||||
|
||||
VA_ALIAS = ast.literal_eval(env.str("VA_ALIAS"))
|
||||
VOSK_MODEL_NAME = env.str("VOSK_MODEL_NAME")
|
||||
MICROPHONE_INDEX = env.int("MICROPHONE_INDEX")
|
||||
PICOVOICE_TOKEN = env.str("PICOVOICE_TOKEN")
|
||||
|
||||
# home assistant
|
||||
HOME_ASSISTANT_URL = "http://192.168.0.112:9999/api"
|
||||
HOME_ASSISTANT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI5NjczNDZjYjc2YzI0YWQzODdhMmUwMmM2MjViZGVjZCIsImlhdCI6MTcxNDQ3MzkzNywiZXhwIjoyMDI5ODMzOTM3fQ.TATpIMXivJOioCtUI8PKg6gyTQYMG6bur6enm6NxjtY"
|
||||
HOME_ASSISTANT_URL = env.str("HOME_ASSISTANT_URL")
|
||||
HOME_ASSISTANT_TOKEN = env.str("HOME_ASSISTANT_TOKEN")
|
||||
|
||||
# weather
|
||||
WEATHER_DEFAULT_CITY = env.str("WEATHER_DEFAULT_CITY")
|
||||
WEATHER_URL = env.str("WEATHER_URL")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,27 @@
|
||||
import requests
|
||||
import yaml
|
||||
from fuzzywuzzy import process
|
||||
from requests import Response
|
||||
|
||||
from data import config
|
||||
|
||||
|
||||
class HomeAssistant:
|
||||
"""
|
||||
Модуль home assistant для работы с его api
|
||||
"""
|
||||
def __init__(self):
|
||||
self.url = "http://192.168.0.112:9999/api"
|
||||
self.token = config.HOME_ASSISTANT_TOKEN
|
||||
self.HA_CMD_LIST = yaml.safe_load(open('data/home_assistant_entities.yaml', encoding='utf8'))
|
||||
|
||||
def get_info(self, state):
|
||||
def get_info(self, state: str) -> Response:
|
||||
"""
|
||||
Функция для получения информации о заданном entity
|
||||
|
||||
:param state: str - объект в home assistant информацию о котором надо узнать
|
||||
:return: Response - ответ от сервера api
|
||||
"""
|
||||
response = requests.get(
|
||||
url=f"{self.url}/states",
|
||||
headers={
|
||||
@@ -23,7 +33,13 @@ class HomeAssistant:
|
||||
return entity
|
||||
return response
|
||||
|
||||
def send_process(self, command="выключи телевизор"):
|
||||
def send_process(self, command: str = "выключи телевизор") -> bool:
|
||||
"""
|
||||
Функция для отправки запроса о выполнении команды к api
|
||||
|
||||
:param command: str - команда в виде строки
|
||||
:return: bool - удачная ли отправка запроса к api
|
||||
"""
|
||||
response = requests.post(
|
||||
url=f"{self.url}/services/conversation/process",
|
||||
json={"text": command},
|
||||
@@ -37,6 +53,13 @@ class HomeAssistant:
|
||||
return False
|
||||
|
||||
def voice_to_name(self, voice: str) -> str:
|
||||
"""
|
||||
Функция для неточного сравнивания входной строки голоса
|
||||
и списка устройств дял которых можно узнать информацию
|
||||
|
||||
:param voice: str - распознанная фраза без проверки по списку
|
||||
:return: str - найденный объект для получения информации
|
||||
"""
|
||||
words = voice.lower().split()
|
||||
best_match = None
|
||||
highest_score = 0
|
||||
@@ -47,13 +70,20 @@ class HomeAssistant:
|
||||
best_match = result
|
||||
return best_match
|
||||
|
||||
def validate_info(self, name: str):
|
||||
def validate_info(self, name: str) -> str:
|
||||
"""
|
||||
Функция для получения готовой строки информации entity по его имени.
|
||||
Эта строка готова для произношения
|
||||
|
||||
:param name: str - имя entity для нахождения информации о нём
|
||||
:return: str - готовая строка для найденного по имени объекта для её произношения
|
||||
"""
|
||||
answer = name
|
||||
entity_config = self.HA_CMD_LIST.get(name)
|
||||
if entity_config:
|
||||
# Создание словаря, разделяя каждый элемент конфигурации на ключ и значение
|
||||
entity_details = {item.split(':')[0]: item.split(':')[1] for item in entity_config}
|
||||
entity_id = entity_details.pop("entity_id", None)
|
||||
entity_id = entity_details.pop("entity_id", "robot")
|
||||
if entity_id:
|
||||
responses = self.get_info(entity_id)
|
||||
for attribute_path, label in entity_details.items():
|
||||
|
||||
+23
-4
@@ -11,17 +11,22 @@ from fuzzywuzzy import fuzz
|
||||
from pvrecorder import PvRecorder
|
||||
|
||||
from data import config
|
||||
from modules import HomeAssistant
|
||||
from modules import HomeAssistant, MediaPlayerController, Weather
|
||||
from utils import download_models, execute_cmd, play
|
||||
|
||||
|
||||
class Jarvis:
|
||||
"""
|
||||
Это основной модуль голосового ассистента
|
||||
"""
|
||||
def __init__(self):
|
||||
download_models.install_vosk_model()
|
||||
self.recorder = None
|
||||
self.CDIR = os.getcwd()
|
||||
self.VA_CMD_LIST = yaml.safe_load(open('data/commands.yaml', encoding='utf8'))
|
||||
self.home_assistant = HomeAssistant.HomeAssistant()
|
||||
self.media_player_controller = MediaPlayerController.MediaPlayerController()
|
||||
self.weather = Weather.Weather()
|
||||
self.porcupine = pvporcupine.create(
|
||||
access_key=config.PICOVOICE_TOKEN,
|
||||
keywords=['jarvis'],
|
||||
@@ -62,9 +67,15 @@ class Jarvis:
|
||||
print(f"Unexpected {err=}, {type(err)=}")
|
||||
raise
|
||||
|
||||
def va_respond(self, voice: str):
|
||||
def va_respond(self, voice: str) -> bool:
|
||||
"""
|
||||
Функция предсказывает команду
|
||||
|
||||
:param voice: str - распознанная строка
|
||||
:return: bool - распознана или нет команда
|
||||
"""
|
||||
print(f"Распознано: {voice}")
|
||||
for x in config.VA_ALIAS + config.VA_TBR:
|
||||
for x in config.VA_ALIAS:
|
||||
voice = voice.replace(x, "").strip()
|
||||
rc = {'cmd': '', 'percent': 0}
|
||||
for c, v in self.VA_CMD_LIST.items():
|
||||
@@ -84,5 +95,13 @@ class Jarvis:
|
||||
execute_cmd.execute_cmd(self, rc['cmd'], rc['recognized_phrase'], voice)
|
||||
return True
|
||||
|
||||
def play(self, phrase, wait_done=True):
|
||||
def play(self, phrase: str, wait_done: bool = True):
|
||||
"""
|
||||
Функция для запуска голосовой команды
|
||||
|
||||
:param self: modules.Jarvis - объект основного модуля
|
||||
:param phrase: str - фраза для запуска голосовой команды
|
||||
:param wait_done: bool - нужно-ли ждать окончания фразы
|
||||
:return:
|
||||
"""
|
||||
play.play(self, phrase, wait_done)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
|
||||
class MediaPlayerController:
|
||||
"""
|
||||
Модуль для манипуляции музыкой
|
||||
"""
|
||||
def __init__(self):
|
||||
self.os_type = platform.system()
|
||||
|
||||
def play_pause(self) -> None:
|
||||
"""
|
||||
Запуск/остановка музыки
|
||||
|
||||
:return:
|
||||
"""
|
||||
if self.os_type == 'Windows':
|
||||
self._windows_play_pause()
|
||||
elif self.os_type == 'Linux':
|
||||
self._linux_control("play-pause")
|
||||
|
||||
def next_track(self) -> None:
|
||||
"""
|
||||
Включает следующею композицию
|
||||
|
||||
:return:
|
||||
"""
|
||||
if self.os_type == 'Windows':
|
||||
self._windows_control("next")
|
||||
elif self.os_type == 'Linux':
|
||||
self._linux_control("next")
|
||||
|
||||
def previous_track(self) -> None:
|
||||
"""
|
||||
Включает предыдущею композицию
|
||||
|
||||
:return:
|
||||
"""
|
||||
if self.os_type == 'Windows':
|
||||
self._windows_control("previous")
|
||||
elif self.os_type == 'Linux':
|
||||
self._linux_control("previous")
|
||||
|
||||
def _windows_play_pause(self) -> None:
|
||||
"""
|
||||
Запуск/остановка музыки в windows
|
||||
|
||||
:return:
|
||||
"""
|
||||
import win32con
|
||||
self.key_press(win32con.VK_MEDIA_PLAY_PAUSE)
|
||||
|
||||
def _windows_control(self, action: str) -> None:
|
||||
"""
|
||||
Включает предыдущею или следующею композицию в windows
|
||||
|
||||
:return:
|
||||
"""
|
||||
import win32con
|
||||
if action == "next":
|
||||
self.key_press(win32con.VK_MEDIA_NEXT_TRACK)
|
||||
elif action == "previous":
|
||||
self.key_press(win32con.VK_MEDIA_PREV_TRACK)
|
||||
|
||||
@staticmethod
|
||||
def key_press(key_code: str) -> None:
|
||||
"""
|
||||
Симуляция нажатия и отпускания клавиши
|
||||
|
||||
:param key_code: str - какую кнопку нажать
|
||||
:return:
|
||||
"""
|
||||
import win32api
|
||||
import win32con
|
||||
win32api.keybd_event(key_code, 0, 0, 0)
|
||||
win32api.keybd_event(key_code, 0, win32con.KEYEVENTF_KEYUP, 0)
|
||||
|
||||
@staticmethod
|
||||
def _linux_control(command: str) -> None:
|
||||
"""
|
||||
Запускает команду для linux систем
|
||||
|
||||
:param command: str - команда для запуска
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
subprocess.run(["playerctl", command], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Failed to {command}: {e}")
|
||||
@@ -0,0 +1,50 @@
|
||||
import json
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from curl_cffi import requests
|
||||
from fuzzywuzzy import fuzz
|
||||
|
||||
from data.config import WEATHER_DEFAULT_CITY, WEATHER_URL
|
||||
|
||||
|
||||
class Weather:
|
||||
def __init__(self):
|
||||
self.default_city = WEATHER_DEFAULT_CITY
|
||||
self.url = WEATHER_URL
|
||||
|
||||
def get_info(self, city: str) -> str:
|
||||
try:
|
||||
response = requests.get(f"{self.url}/{city}", impersonate="chrome110")
|
||||
soup = BeautifulSoup(response.text, "html.parser")
|
||||
card = soup.find(
|
||||
"div",
|
||||
class_=["fact", "fact_prec_rain-low", "card", "card_size_big"]
|
||||
)
|
||||
info = card.find(
|
||||
"div",
|
||||
class_=["fact__temp-wrap"]
|
||||
)
|
||||
temp = info.find(
|
||||
"span",
|
||||
class_=["temp__value", "temp__value_with-unit"]
|
||||
).text
|
||||
weather = info.find(
|
||||
"div",
|
||||
class_=["link__condition", "day-anchor i-bem"]
|
||||
).text.lower()
|
||||
return f"За окном {temp}, {weather}"
|
||||
except AttributeError:
|
||||
return self.get_info(self.default_city)
|
||||
|
||||
def validate_city(self, voice: str) -> str:
|
||||
validate_voice = voice.split(" ")[-1]
|
||||
rc = {'cmd': '', 'percent': 0}
|
||||
data = json.load(open("data/weather_city.json"))
|
||||
for ru, en in data.items():
|
||||
vrt = fuzz.ratio(validate_voice.lower(), ru.lower())
|
||||
if vrt > rc['percent']:
|
||||
rc['cmd'] = en.lower()
|
||||
rc['percent'] = vrt
|
||||
if rc['percent'] > 80:
|
||||
return rc['cmd']
|
||||
return self.default_city
|
||||
Generated
+219
-1
@@ -44,6 +44,41 @@ files = [
|
||||
[package.extras]
|
||||
test = ["tox"]
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.12.3"
|
||||
description = "Screen-scraping library"
|
||||
optional = false
|
||||
python-versions = ">=3.6.0"
|
||||
files = [
|
||||
{file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"},
|
||||
{file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
soupsieve = ">1.2"
|
||||
|
||||
[package.extras]
|
||||
cchardet = ["cchardet"]
|
||||
chardet = ["chardet"]
|
||||
charset-normalizer = ["charset-normalizer"]
|
||||
html5lib = ["html5lib"]
|
||||
lxml = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "bs4"
|
||||
version = "0.0.2"
|
||||
description = "Dummy package for Beautiful Soup (beautifulsoup4)"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "bs4-0.0.2-py2.py3-none-any.whl", hash = "sha256:abf8742c0805ef7f662dce4b51cca104cffe52b835238afc169142ab9b3fbccc"},
|
||||
{file = "bs4-0.0.2.tar.gz", hash = "sha256:a48685c58f50fe127722417bae83fe6badf500d54b55f7e39ffe43b798653925"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
beautifulsoup4 = "*"
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2024.2.2"
|
||||
@@ -303,6 +338,34 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pill
|
||||
test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
|
||||
test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"]
|
||||
|
||||
[[package]]
|
||||
name = "curl-cffi"
|
||||
version = "0.6.3"
|
||||
description = "libcurl ffi bindings for Python, with impersonation support."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ac60ac08f07640bd9ee6ee44310748931a3d49a7c8e878745f1817b46ff0719d"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d78a609c3b984df9a14022c0b5fc59c1c643c39fc4cb9100e110f7551339a194"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:760b7b837c86626f2c9518c3bad42aad3b6ccb455499b648bc98e8dee9f73891"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5423c2f53f8889bcc9ce42455fc1c0c9487b480944f66aaa6ed5ce81e0fc5540"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b4712bc9a8a0d933aef7051eaa5448b9a1c662f25dd83967dbdd46aa3e418c0"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5d659acbe051805b9f9c82a7725d534b5842c1a9291159e7733e7c92782ef80b"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ea9b04df071368d13b02c51e87e3e51b46b924be61681fc280cb9633b42dac2c"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-win32.whl", hash = "sha256:0f37e3d761e37173462dbc95ae4216165dacef21f0d9ab6bb6802003516a156f"},
|
||||
{file = "curl_cffi-0.6.3-cp38-abi3-win_amd64.whl", hash = "sha256:dd36513cd46eb8f2751d45e3aa47a989421d3f3a2bcc54abab487ae38549d91b"},
|
||||
{file = "curl_cffi-0.6.3.tar.gz", hash = "sha256:0d2d07467590d66982f29a8dc9050b6a1f41a6c4bb44dcbf24108b13cf71a797"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2024.2.2"
|
||||
cffi = ">=1.12.0"
|
||||
|
||||
[package.extras]
|
||||
build = ["cibuildwheel", "wheel"]
|
||||
dev = ["autoflake (==1.4)", "charset-normalizer (>=3.3.2,<4)", "coverage (==6.4.1)", "cryptography (==38.0.3)", "flake8 (==6.0.0)", "flake8-bugbear (==22.7.1)", "flake8-pie (==0.15.0)", "httpx (==0.23.1)", "mypy (==1.9.0)", "pytest (==7.1.2)", "pytest-asyncio (==0.19.0)", "pytest-trio (==0.7.0)", "ruff (==0.3.3)", "trio (==0.21.0)", "trio-typing (==0.7.0)", "trustme (==0.9.0)", "types-certifi (==2021.10.8.2)", "uvicorn (==0.18.3)", "websockets (==11.0.3)"]
|
||||
test = ["charset-normalizer (>=3.3.2,<4)", "cryptography (==38.0.3)", "fastapi (==0.100.0)", "httpx (==0.23.1)", "proxy.py (==2.4.3)", "pytest (==7.1.2)", "pytest-asyncio (==0.19.0)", "pytest-trio (==0.7.0)", "python-multipart (==0.0.6)", "trio (==0.21.0)", "trio-typing (==0.7.0)", "trustme (==0.9.0)", "types-certifi (==2021.10.8.2)", "uvicorn (==0.18.3)", "websockets (==11.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "cycler"
|
||||
version = "0.12.1"
|
||||
@@ -329,6 +392,37 @@ files = [
|
||||
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "environs"
|
||||
version = "11.0.0"
|
||||
description = "simplified environment variable parsing"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "environs-11.0.0-py3-none-any.whl", hash = "sha256:e0bcfd41c718c07a7db422f9109e490746450da38793fe4ee197f397b9343435"},
|
||||
{file = "environs-11.0.0.tar.gz", hash = "sha256:069727a8f73d8ba8d033d3cd95c0da231d44f38f1da773bf076cef168d312ee8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
marshmallow = ">=3.13.0"
|
||||
python-dotenv = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["environs[tests]", "pre-commit (>=3.5,<4.0)", "tox"]
|
||||
django = ["dj-database-url", "dj-email-url", "django-cache-url"]
|
||||
tests = ["environs[django]", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "fake-useragent"
|
||||
version = "1.5.1"
|
||||
description = "Up-to-date simple useragent faker with real world database"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "fake-useragent-1.5.1.tar.gz", hash = "sha256:6387269f5a2196b5ba7ed8935852f75486845a1c95c50e72460e6a8e762f5c49"},
|
||||
{file = "fake_useragent-1.5.1-py3-none-any.whl", hash = "sha256:57415096557c8a4e23b62a375c21c55af5fd4ba30549227f562d2c4f5b60e3b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.13.4"
|
||||
@@ -974,6 +1068,25 @@ files = [
|
||||
{file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marshmallow"
|
||||
version = "3.21.2"
|
||||
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "marshmallow-3.21.2-py3-none-any.whl", hash = "sha256:70b54a6282f4704d12c0a41599682c5c5450e843b9ec406308653b47c59648a1"},
|
||||
{file = "marshmallow-3.21.2.tar.gz", hash = "sha256:82408deadd8b33d56338d2182d455db632c6313aa2af61916672146bb32edc56"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=17.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"]
|
||||
docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"]
|
||||
tests = ["pytest", "pytz", "simplejson"]
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib"
|
||||
version = "3.8.4"
|
||||
@@ -1433,6 +1546,78 @@ files = [
|
||||
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pandas"
|
||||
version = "2.2.2"
|
||||
description = "Powerful data structures for data analysis, time series, and statistics"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"},
|
||||
{file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = [
|
||||
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
||||
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
||||
]
|
||||
python-dateutil = ">=2.8.2"
|
||||
pytz = ">=2020.1"
|
||||
tzdata = ">=2022.7"
|
||||
|
||||
[package.extras]
|
||||
all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"]
|
||||
aws = ["s3fs (>=2022.11.0)"]
|
||||
clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"]
|
||||
compression = ["zstandard (>=0.19.0)"]
|
||||
computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"]
|
||||
consortium-standard = ["dataframe-api-compat (>=0.1.7)"]
|
||||
excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"]
|
||||
feather = ["pyarrow (>=10.0.1)"]
|
||||
fss = ["fsspec (>=2022.11.0)"]
|
||||
gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"]
|
||||
hdf5 = ["tables (>=3.8.0)"]
|
||||
html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"]
|
||||
mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"]
|
||||
output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"]
|
||||
parquet = ["pyarrow (>=10.0.1)"]
|
||||
performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"]
|
||||
plot = ["matplotlib (>=3.6.3)"]
|
||||
postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"]
|
||||
pyarrow = ["pyarrow (>=10.0.1)"]
|
||||
spss = ["pyreadstat (>=1.2.0)"]
|
||||
sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"]
|
||||
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"]
|
||||
xml = ["lxml (>=4.9.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "10.3.0"
|
||||
@@ -1713,6 +1898,17 @@ files = [
|
||||
[package.dependencies]
|
||||
Levenshtein = "0.23.0"
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2024.1"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"},
|
||||
{file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.1"
|
||||
@@ -2105,6 +2301,17 @@ cffi = ">=1.0"
|
||||
[package.extras]
|
||||
numpy = ["numpy"]
|
||||
|
||||
[[package]]
|
||||
name = "soupsieve"
|
||||
version = "2.5"
|
||||
description = "A modern CSS selector implementation for Beautiful Soup."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"},
|
||||
{file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soxr"
|
||||
version = "0.3.7"
|
||||
@@ -2339,6 +2546,17 @@ files = [
|
||||
{file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2024.1"
|
||||
description = "Provider of IANA time zone data"
|
||||
optional = false
|
||||
python-versions = ">=2"
|
||||
files = [
|
||||
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
|
||||
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.2.1"
|
||||
@@ -2460,4 +2678,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "80e7f3585f34cc051c27d91abbe3f4bff80e5ea9fa403103eeed5728b14c2cc5"
|
||||
content-hash = "ed456a985fc886096ff16cdca62c4381aab1fc6563761770583f1d6b20006ce3"
|
||||
|
||||
@@ -27,6 +27,11 @@ torchaudio = "^2.1.1+cpu"
|
||||
ollama = "^0.1.6"
|
||||
ruff = "^0.4.2"
|
||||
noisereduce = "^3.0.2"
|
||||
environs = "^11.0.0"
|
||||
bs4 = "^0.0.2"
|
||||
fake-useragent = "^1.5.1"
|
||||
curl-cffi = "^0.6.3"
|
||||
pandas = "^2.2.2"
|
||||
|
||||
|
||||
[[tool.poetry.source]]
|
||||
|
||||
+22
-11
@@ -4,23 +4,34 @@ import sys
|
||||
from data import config
|
||||
|
||||
|
||||
def install_vosk_model():
|
||||
def install_vosk_model() -> None:
|
||||
"""
|
||||
Функция устанавливает заданную в конфигурационном файле модели
|
||||
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
open('data/model_small/README')
|
||||
except Exception as e:
|
||||
print(e)
|
||||
if sys.platform == "linux" or sys.platform == "linux2":
|
||||
os.system(f"wget https://alphacephei.com/vosk/models/{config.MODEL_NAME}.zip")
|
||||
os.system(f"unzip {config.MODEL_NAME}.zip")
|
||||
os.system(f"mv {config.MODEL_NAME} data/model_small")
|
||||
os.system(f"rm -rf {config.MODEL_NAME}.zip")
|
||||
os.system(
|
||||
f"wget https://alphacephei.com/vosk/models/{config.VOSK_MODEL_NAME}.zip"
|
||||
)
|
||||
os.system(f"unzip {config.VOSK_MODEL_NAME}.zip")
|
||||
os.system(f"mv {config.VOSK_MODEL_NAME} data/model_small")
|
||||
os.system(f"rm -rf {config.VOSK_MODEL_NAME}.zip")
|
||||
elif sys.platform == "darwin":
|
||||
os.system(f"curl https://alphacephei.com/vosk/models/{config.MODEL_NAME}.zip")
|
||||
os.system(f"unzip {config.MODEL_NAME}.zip")
|
||||
os.system(f"mv {config.MODEL_NAME} data/model_small")
|
||||
os.system(f"rm -rf {config.MODEL_NAME}.zip")
|
||||
os.system(
|
||||
f"curl https://alphacephei.com/vosk/models/{config.VOSK_MODEL_NAME}.zip"
|
||||
)
|
||||
os.system(f"unzip {config.VOSK_MODEL_NAME}.zip")
|
||||
os.system(f"mv {config.VOSK_MODEL_NAME} data/model_small")
|
||||
os.system(f"rm -rf {config.VOSK_MODEL_NAME}.zip")
|
||||
elif sys.platform == "win32":
|
||||
os.system(f"curl https://alphacephei.com/vosk/models/{config.MODEL_NAME}.zip --output 1.zip")
|
||||
os.system(
|
||||
f"curl https://alphacephei.com/vosk/models/{config.VOSK_MODEL_NAME}.zip --output 1.zip"
|
||||
)
|
||||
os.system('powershell -command "Expand-Archive 1.zip ./"')
|
||||
os.system(f"rename {config.MODEL_NAME} data/model_small")
|
||||
os.system(f"rename {config.VOSK_MODEL_NAME} data/model_small")
|
||||
os.system("del /s /q 1.zip")
|
||||
|
||||
+30
-1
@@ -1,4 +1,21 @@
|
||||
def execute_cmd(self, cmd: str, recognized_phrase: str, voice: str):
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from modules.Jarvis import Jarvis
|
||||
else:
|
||||
Jarvis = None
|
||||
|
||||
|
||||
def execute_cmd(self: Jarvis, cmd: str, recognized_phrase: str, voice: str) -> None:
|
||||
"""
|
||||
Функция выполняет полученные команды
|
||||
|
||||
:param self: modules.Jarvis - объект основного модуля
|
||||
:param cmd: str - команда которую функция должна выполнить
|
||||
:param recognized_phrase: str - распознанная фраза из списка фраз
|
||||
:param voice: str - распознанная фраза без проверки по списку
|
||||
:return:
|
||||
"""
|
||||
if cmd == 'thanks':
|
||||
self.play("thanks")
|
||||
elif cmd == 'stupid':
|
||||
@@ -7,9 +24,21 @@ def execute_cmd(self, cmd: str, recognized_phrase: str, voice: str):
|
||||
self.play("off", True)
|
||||
self.porcupine.delete()
|
||||
exit(0)
|
||||
elif cmd == 'music_on':
|
||||
self.media_player_controller.play_pause()
|
||||
elif cmd == 'music_off':
|
||||
self.media_player_controller.play_pause()
|
||||
elif cmd == 'music_next':
|
||||
self.media_player_controller.next_track()
|
||||
elif cmd == 'music_previous':
|
||||
self.media_player_controller.previous_track()
|
||||
elif cmd == 'home_assistant_execute':
|
||||
self.home_assistant.send_process(recognized_phrase)
|
||||
elif cmd == 'home_assistant_get':
|
||||
entity_name = self.home_assistant.voice_to_name(voice)
|
||||
entity_info = self.home_assistant.validate_info(entity_name)
|
||||
print(entity_info)
|
||||
elif cmd == 'weather':
|
||||
city = self.weather.validate_city(voice)
|
||||
city_info = self.weather.get_info(city)
|
||||
print(city_info)
|
||||
|
||||
+9
-1
@@ -3,7 +3,15 @@ import random
|
||||
import simpleaudio as sa
|
||||
|
||||
|
||||
def play(self, phrase, wait_done=True):
|
||||
def play(self, phrase: str, wait_done: bool = True) -> None:
|
||||
"""
|
||||
Функция для запуска голосовой команды
|
||||
|
||||
:param self: modules.Jarvis - объект основного модуля
|
||||
:param phrase: str - фраза для запуска голосовой команды
|
||||
:param wait_done: bool - нужно-ли ждать окончания фразы
|
||||
:return:
|
||||
"""
|
||||
filename = None
|
||||
file_array = ["not_found", "thanks", "run", "stupid", "ready", "off"]
|
||||
if phrase == "greet":
|
||||
|
||||
Reference in New Issue
Block a user