First working version

This commit is contained in:
Michael Hansen
2024-01-14 22:19:01 -06:00
parent 316427948e
commit 8063f5b773
12 changed files with 740 additions and 439 deletions
+210 -72
View File
@@ -3,25 +3,38 @@ import itertools
import re
import shutil
from pathlib import Path
from typing import Optional, Dict
from typing import Dict, Optional
from .const import Settings, SatelliteType, WakeWordSystem, LOCAL_DIR
from .whiptail import msgbox, menu, radiolist, run_with_gauge, yesno, error
from .const import LOCAL_DIR, SatelliteType, Settings, WakeWordSystem
from .whiptail import error, inputbox, menu, msgbox, radiolist, run_with_gauge, yesno
def configure_wake_word(settings: Settings) -> None:
if settings.satellite_type != SatelliteType.WAKE:
if settings.satellite.type != SatelliteType.WAKE:
if not yesno("Set satellite type to local wake word?"):
return
settings.satellite_type = SatelliteType.WAKE
settings.satellite.type = SatelliteType.WAKE
settings.save()
def star(ww_system: WakeWordSystem) -> str:
return (
f"{ww_system.value} [*]"
if settings.wake.system == ww_system
else ww_system.value
)
choice: Optional[str] = None
while True:
choice = menu(
"Main > Wake Word",
[("system", "Wake Word System"), ("wake_word", "Wake Word")],
[
("system", "Wake Word System"),
("wake_word", "Choose Wake Word"),
("openWakeWord", star(WakeWordSystem.OPENWAKEWORD)),
("porcupine1", star(WakeWordSystem.PORCUPINE1)),
("snowboy", star(WakeWordSystem.SNOWBOY)),
],
selected_item=choice,
menu_args=["--ok-button", "Select", "--cancel-button", "Back"],
)
@@ -30,7 +43,7 @@ def configure_wake_word(settings: Settings) -> None:
wake_word_system = radiolist(
"Wake Word System:",
[v.value for v in WakeWordSystem],
settings.wake_word_system,
settings.wake.system,
)
if wake_word_system is None:
continue
@@ -39,6 +52,12 @@ def configure_wake_word(settings: Settings) -> None:
install_wake_word(settings, wake_word_system)
elif choice == "wake_word":
select_wake_word(settings)
elif choice == "openWakeWord":
configure_openWakeWord(settings)
elif choice == "porcupine1":
configure_porcupine1(settings)
elif choice == "snowboy":
configure_snowboy(settings)
else:
break
@@ -75,8 +94,7 @@ def install_wake_word(settings: Settings, wake_word_system: WakeWordSystem) -> N
msgbox("openWakeWord installed successfully")
settings.wake_word_system = wake_word_system
settings.wake_word.setdefault(WakeWordSystem.OPENWAKEWORD, "ok_nabu")
settings.wake.system = wake_word_system
settings.save()
return
@@ -110,7 +128,7 @@ def install_wake_word(settings: Settings, wake_word_system: WakeWordSystem) -> N
else:
msgbox("porcupine1 installed successfully")
settings.wake_word_system = wake_word_system
settings.wake.system = wake_word_system
settings.save()
return
@@ -144,21 +162,19 @@ def install_wake_word(settings: Settings, wake_word_system: WakeWordSystem) -> N
else:
msgbox("snowboy installed successfully")
settings.wake_word_system = wake_word_system
settings.wake.system = wake_word_system
settings.save()
return
def select_wake_word(settings: Settings) -> None:
if settings.wake_word_system == WakeWordSystem.OPENWAKEWORD:
if settings.wake.system == WakeWordSystem.OPENWAKEWORD:
oww_dir = LOCAL_DIR / "wyoming-openwakeword"
if not oww_dir.exists():
msgbox("openWakeWord is not installed")
return
custom_wake_word_dir = (
LOCAL_DIR / "custom-wake-words" / WakeWordSystem.OPENWAKEWORD.value
)
custom_wake_word_dir = LOCAL_DIR / "custom-wake-words" / "openWakeWord"
custom_wake_word_dir.mkdir(parents=True, exist_ok=True)
community_wake_word_dir = LOCAL_DIR / "home-assistant-wakewords-collection"
@@ -187,64 +203,25 @@ def select_wake_word(settings: Settings) -> None:
ww_paths[ww_name] = ww_path
items = [("__community__", "Download Community Wake Words")] + list(
sorted(ww_paths.keys())
)
items = sorted(list(ww_paths.keys()))
wake_word = radiolist(
"Wake Word:", items, settings.wake_word.get(WakeWordSystem.OPENWAKEWORD)
"Wake Word:", items, settings.wake.openwakeword.wake_word
)
if wake_word is None:
break
if wake_word == "__community__":
if not community_wake_word_dir.exists():
success = run_with_gauge(
"Downloading community wake words...",
[
[
"git",
"clone",
"https://github.com/fwartner/home-assistant-wakewords-collection.git",
str(community_wake_word_dir),
]
],
)
if not success:
error("downloading community wake words")
else:
success = run_with_gauge(
"Updating community wake words...",
[
[
"git",
"-C",
str(community_wake_word_dir),
"pull",
"origin",
"main",
]
],
)
if not success:
error("updating community wake words")
continue
wake_word_path = ww_paths[wake_word]
if wake_word_path.is_relative_to(community_wake_word_dir):
# Copy to custom directory
shutil.copy(wake_word_path, custom_wake_word_dir)
settings.wake_word[WakeWordSystem.OPENWAKEWORD] = wake_word
settings.wake.openwakeword.wake_word = wake_word
settings.save()
break
return
if settings.wake_word_system == WakeWordSystem.PORCUPINE1:
if settings.wake.system == WakeWordSystem.PORCUPINE1:
porcupine1_dir = LOCAL_DIR / "wyoming-porcupine1"
if not porcupine1_dir.exists():
msgbox("porcupine1 is not installed")
@@ -262,26 +239,21 @@ def select_wake_word(settings: Settings) -> None:
)
wake_word = radiolist(
"Wake Word:",
ww_names,
settings.wake_word.get(WakeWordSystem.PORCUPINE1),
"Wake Word:", ww_names, settings.wake.porcupine1.wake_word
)
if wake_word is not None:
settings.wake_word[WakeWordSystem.PORCUPINE1] = wake_word
settings.wake.porcupine1.wake_word = wake_word
settings.save()
return
if settings.wake_word_system == WakeWordSystem.SNOWBOY:
if settings.wake.system == WakeWordSystem.SNOWBOY:
snowboy_dir = LOCAL_DIR / "wyoming-snowboy"
if not snowboy_dir.exists():
msgbox("snowboy is not installed")
return
custom_wake_word_dir = (
LOCAL_DIR / "custom-wake-words" / WakeWordSystem.SNOWBOY.value
)
custom_wake_word_dir = LOCAL_DIR / "custom-wake-words" / "snowboy"
custom_wake_word_dir.mkdir(parents=True, exist_ok=True)
builtin_wake_words = (snowboy_dir / "wyoming_snowboy" / "data").glob("*.umdl")
@@ -297,12 +269,178 @@ def select_wake_word(settings: Settings) -> None:
)
)
wake_word = radiolist(
"Wake Word:", ww_names, settings.wake_word.get(WakeWordSystem.SNOWBOY)
)
wake_word = radiolist("Wake Word:", ww_names, settings.wake.snowboy.wake_word)
if wake_word is not None:
settings.wake_word[WakeWordSystem.SNOWBOY] = wake_word
settings.wake.snowboy.wake_word = wake_word
settings.save()
return
def configure_openWakeWord(settings: Settings) -> None:
choice: Optional[str] = None
while True:
choice = menu(
"Main > Wake Word > openWakeWord",
[
("community", "Download Community Wake Words"),
("threshold", "Set Threshold"),
("trigger_level", "Set Trigger Level"),
],
selected_item=choice,
menu_args=["--ok-button", "Select", "--cancel-button", "Back"],
)
if choice == "community":
community_wake_word_dir = LOCAL_DIR / "home-assistant-wakewords-collection"
if not community_wake_word_dir.exists():
success = run_with_gauge(
"Downloading community wake words...",
[
[
"git",
"clone",
"https://github.com/fwartner/home-assistant-wakewords-collection.git",
str(community_wake_word_dir),
]
],
)
if not success:
error("downloading community wake words")
else:
success = run_with_gauge(
"Updating community wake words...",
[
[
"git",
"-C",
str(community_wake_word_dir),
"pull",
"origin",
"main",
]
],
)
if not success:
error("updating community wake words")
elif choice == "threshold":
while True:
threshold = inputbox(
"Threshold (0-1, 0.5 = default):",
settings.wake.openwakeword.threshold,
)
if threshold is None:
break
try:
threshold_float = float(threshold)
except ValueError:
msgbox("Invalid value")
continue
if 0 < threshold_float < 1:
settings.wake.openwakeword.threshold = threshold_float
settings.save()
break
msgbox("Threshold must be in (0, 1)")
elif choice == "trigger_level":
while True:
trigger_level = inputbox(
"Trigger Level (> 0, 1 = default):",
settings.wake.openwakeword.trigger_level,
)
if trigger_level is None:
break
try:
trigger_level_int = int(trigger_level)
except ValueError:
msgbox("Invalid value")
continue
if trigger_level_int > 0:
settings.wake.openwakeword.trigger_level = trigger_level_int
settings.save()
break
msgbox("Trigger level must be > 0")
else:
break
def configure_porcupine1(settings: Settings) -> None:
choice: Optional[str] = None
while True:
choice = menu(
"Main > Wake Word > porcupine1",
[
("sensitivity", "Set Sensitivity"),
],
selected_item=choice,
menu_args=["--ok-button", "Select", "--cancel-button", "Back"],
)
if choice == "sensitivity":
while True:
sensitivity = inputbox(
"Sensitivity (0-1, 0.5 = default):",
settings.wake.porcupine1.sensitivity,
)
if sensitivity is None:
break
try:
sensitivity_float = float(sensitivity)
except ValueError:
msgbox("Invalid value")
continue
if 0 < sensitivity_float < 1:
settings.wake.porcupine1.sensitivity = sensitivity_float
settings.save()
break
msgbox("Sensitivity must be in (0, 1)")
else:
break
def configure_snowboy(settings: Settings) -> None:
choice: Optional[str] = None
while True:
choice = menu(
"Main > Wake Word > snowboy",
[
("sensitivity", "Set Sensitivity"),
],
selected_item=choice,
menu_args=["--ok-button", "Select", "--cancel-button", "Back"],
)
if choice == "sensitivity":
while True:
sensitivity = inputbox(
"Sensitivity (0-1, 0.5 = default):",
settings.wake.snowboy.sensitivity,
)
if sensitivity is None:
break
try:
sensitivity_float = float(sensitivity)
except ValueError:
msgbox("Invalid value")
continue
if 0 < sensitivity_float < 1:
settings.wake.snowboy.sensitivity = sensitivity_float
settings.save()
break
msgbox("Sensitivity must be in (0, 1)")
else:
break