feat(hass): use fork of wyoming-oww
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
dd4226e10f
commit
de8b7fd2bb
5 changed files with 144 additions and 150 deletions
|
@ -16,21 +16,6 @@
|
|||
"wyoming"
|
||||
];
|
||||
|
||||
customComponents = builtins.attrValues {
|
||||
# Switched to HASS Ollama integration
|
||||
# inherit (self.legacyPackages.${pkgs.system}.hass-components) home-llm;
|
||||
# Home-llm prompt:
|
||||
/*
|
||||
You are 'Homie', a helpful AI Assistant that controls the devices in a house. Complete the following task as instructed.
|
||||
|
||||
The current time and date is {{ (as_timestamp(now()) | timestamp_custom("%I:%M %p on %A %B %d, %Y", "EST")) }}.
|
||||
|
||||
Services: {{ formatted_tools }}
|
||||
Devices:
|
||||
{{ formatted_devices }}
|
||||
*/
|
||||
};
|
||||
|
||||
config = {
|
||||
assist_pipeline = {};
|
||||
conversation = {};
|
||||
|
@ -48,12 +33,13 @@
|
|||
speaker = 0;
|
||||
};
|
||||
|
||||
openwakeword-docker = {
|
||||
openwakeword = {
|
||||
enable = true;
|
||||
uri = "127.0.0.1:10400";
|
||||
uri = "tcp://127.0.0.1:10400";
|
||||
|
||||
threshold = 0.8;
|
||||
|
||||
customModelsDirectories = ["${wakewords-src}/en/yo_homie"];
|
||||
preloadModels = ["yo_homie"];
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -7,157 +7,69 @@
|
|||
inherit
|
||||
(lib)
|
||||
attrNames
|
||||
escapeShellArgs
|
||||
flatten
|
||||
concatMapStringsSep
|
||||
concatStringsSep
|
||||
filterAttrs
|
||||
hasAttr
|
||||
listToAttrs
|
||||
map
|
||||
mkEnableOption
|
||||
mkForce
|
||||
mkIf
|
||||
mkOption
|
||||
mkOverride
|
||||
nameValuePair
|
||||
optionals
|
||||
splitString
|
||||
types
|
||||
optionalString
|
||||
;
|
||||
|
||||
flatMap = f: list: flatten (map f list);
|
||||
|
||||
cfg = config.services.wyoming.openwakeword-docker;
|
||||
cfg = config.services.wyoming;
|
||||
in {
|
||||
options.services.wyoming.openwakeword-docker = {
|
||||
enable = mkEnableOption "Wyoming openWakeWord server";
|
||||
config = let
|
||||
forkedPkg = import ./pkgs/wyoming-openwakeword.nix pkgs;
|
||||
|
||||
image = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.dockerTools.pullImage {
|
||||
imageName = "docker.io/rhasspy/wyoming-openwakeword";
|
||||
imageDigest = "sha256:88df83cfdaa5a0dd068f79662d06b81479ec7b59a4bea59751ff5d6f68bad24a";
|
||||
sha256 = "1c2yhrhhj1wpd5bcc3zaz1gv8mw8dw5m76cjf42nhf2sgwp2hsjl";
|
||||
finalImageName = "docker.io/rhasspy/wyoming-openwakeword";
|
||||
finalImageTag = "latest";
|
||||
};
|
||||
description = ''
|
||||
The image that docker will use.
|
||||
'';
|
||||
};
|
||||
|
||||
uri = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0:10400";
|
||||
example = "192.0.2.1:5000";
|
||||
description = ''
|
||||
URI to bind the wyoming server to.
|
||||
'';
|
||||
};
|
||||
|
||||
customModelsDirectories = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
description = ''
|
||||
Paths to directories with custom wake word models (*.tflite model files).
|
||||
'';
|
||||
};
|
||||
|
||||
preloadModels = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [
|
||||
"ok_nabu"
|
||||
];
|
||||
example = [
|
||||
# wyoming_openwakeword/models/*.tflite
|
||||
"alexa"
|
||||
"hey_jarvis"
|
||||
"hey_mycroft"
|
||||
"hey_rhasspy"
|
||||
"ok_nabu"
|
||||
];
|
||||
description = ''
|
||||
List of wake word models to preload after startup.
|
||||
'';
|
||||
};
|
||||
|
||||
threshold = mkOption {
|
||||
type = types.float;
|
||||
default = 0.5;
|
||||
description = ''
|
||||
Activation threshold (0-1), where higher means fewer activations.
|
||||
|
||||
See trigger level for the relationship between activations and
|
||||
wake word detections.
|
||||
'';
|
||||
apply = toString;
|
||||
};
|
||||
|
||||
triggerLevel = mkOption {
|
||||
type = types.int;
|
||||
default = 1;
|
||||
description = ''
|
||||
Number of activations before a detection is registered.
|
||||
|
||||
A higher trigger level means fewer detections.
|
||||
'';
|
||||
apply = toString;
|
||||
};
|
||||
|
||||
extraArgs = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [];
|
||||
description = ''
|
||||
Extra arguments to pass to the server commandline.
|
||||
'';
|
||||
apply = escapeShellArgs;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
(cfg.enable
|
||||
&& hasAttr "khepri" config
|
||||
&& hasAttr "rwDataDir" config.khepri)
|
||||
|| !cfg.enable;
|
||||
message = ''
|
||||
The module `docker` from this same flake is needed to use
|
||||
this openwakeword implementation.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
systemd.services = let
|
||||
unitNames = attrNames (
|
||||
filterAttrs (_: v: v.device == "cpu") config.services.wyoming.faster-whisper.servers
|
||||
);
|
||||
in
|
||||
listToAttrs (map (x:
|
||||
whisperUnitNames = attrNames (
|
||||
filterAttrs (_: v: v.device == "cpu") cfg.faster-whisper.servers
|
||||
);
|
||||
in {
|
||||
systemd.services =
|
||||
# https://github.com/felschr/nixos-config/blob/6a0f0bf76e3ae80c1e180ba6f6c7fd3b8e91d2d3/services/home-assistant/wyoming.nix#L29
|
||||
mkIf (cfg.faster-whisper.servers != {})
|
||||
(listToAttrs (map (x:
|
||||
nameValuePair "wyoming-faster-whisper-${x}" {
|
||||
serviceConfig.ProcSubset = mkForce "all";
|
||||
})
|
||||
unitNames);
|
||||
whisperUnitNames))
|
||||
#
|
||||
# openWakeWord
|
||||
// mkIf (cfg.openwakeword.enable) {
|
||||
wyoming-openwakeword.serviceConfig = {
|
||||
MemoryDenyWriteExecute = mkForce (cfg.openwakeword.package != forkedPkg);
|
||||
|
||||
khepri = mkIf cfg.enable {
|
||||
compositions."openwakeword" = {
|
||||
networks.default = {};
|
||||
# changes according to https://github.com/rhasspy/wyoming-openwakeword/pull/27
|
||||
ExecStart = mkForce (concatStringsSep " " [
|
||||
"${cfg.openwakeword.package}/bin/wyoming-openwakeword"
|
||||
|
||||
services."openwakeword" = {
|
||||
image = cfg.image;
|
||||
restart = "always";
|
||||
networks = ["default"];
|
||||
"--uri ${cfg.openwakeword.uri}"
|
||||
"--threshold ${cfg.openwakeword.threshold}"
|
||||
|
||||
volumes = map (dir: "${toString dir}:${toString dir}") cfg.customModelsDirectories;
|
||||
cmd =
|
||||
(flatMap (model: ["--preload-model" model]) cfg.preloadModels)
|
||||
++ (flatMap (dir: ["--custom-model-dir" (toString dir)]) cfg.customModelsDirectories)
|
||||
++ ["--threshold" cfg.threshold]
|
||||
++ ["--trigger-level" cfg.triggerLevel]
|
||||
++ optionals (cfg.extraArgs != "") (splitString " " cfg.extraArgs);
|
||||
(concatMapStringsSep " "
|
||||
(dir: "--custom-model-dir ${toString dir}")
|
||||
cfg.openwakeword.customModelsDirectories)
|
||||
|
||||
ports = ["${cfg.uri}:10400"];
|
||||
# removed option https://github.com/rhasspy/wyoming-openwakeword/pull/27#issuecomment-2211822998
|
||||
(optionalString
|
||||
(cfg.openwakeword.package != forkedPkg)
|
||||
(concatMapStringsSep " " (model: "--preload-model ${model}") cfg.openwakeword.preloadModels))
|
||||
|
||||
# removed option since preloading was removed
|
||||
(optionalString
|
||||
(cfg.openwakeword.package != forkedPkg)
|
||||
"--trigger-level ${cfg.openwakeword.triggerLevel}")
|
||||
|
||||
"${cfg.openwakeword.extraArgs}"
|
||||
]);
|
||||
};
|
||||
};
|
||||
|
||||
services.wyoming.openwakeword = mkIf (cfg.openwakeword.enable) {
|
||||
package = mkOverride 900 forkedPkg;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
43
nixosModules/wyoming-plus/pkgs/openwakeword.nix
Normal file
43
nixosModules/wyoming-plus/pkgs/openwakeword.nix
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
fetchFromGitHub,
|
||||
fetchpatch,
|
||||
python3Packages,
|
||||
speexdsp-ns,
|
||||
...
|
||||
}:
|
||||
python3Packages.buildPythonApplication rec {
|
||||
pname = "openwakeword";
|
||||
version = "0.6.0";
|
||||
pyproject = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "dscripka";
|
||||
repo = "openWakeWord";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-QsXV9REAHdP0Y0fVZuU+Gt9+gcPMB60bc3DOMDYuaDM=";
|
||||
};
|
||||
|
||||
# Patch upstream to enable use of full tensorflow dep
|
||||
pythonRemoveDeps = ["tflite-runtime"];
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
url = "https://github.com/dscripka/openWakeWord/pull/178/commits/99cd87e8898348255e864540e43bab17ce0576d6.patch";
|
||||
hash = "sha256-xveMBZTcYfT8LKiiStqYjjOdUOM/v4taQzSewo97Bfc=";
|
||||
})
|
||||
];
|
||||
|
||||
nativeBuildInputs = with python3Packages; [
|
||||
setuptools
|
||||
];
|
||||
|
||||
propagatedBuildInputs =
|
||||
(with python3Packages; [
|
||||
onnxruntime
|
||||
tensorflow-bin
|
||||
tqdm
|
||||
scipy
|
||||
scikit-learn
|
||||
requests
|
||||
])
|
||||
++ [speexdsp-ns];
|
||||
}
|
21
nixosModules/wyoming-plus/pkgs/speexdsp-ns.nix
Normal file
21
nixosModules/wyoming-plus/pkgs/speexdsp-ns.nix
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
fetchFromGitHub,
|
||||
python3Packages,
|
||||
speexdsp,
|
||||
swig,
|
||||
...
|
||||
}:
|
||||
python3Packages.buildPythonApplication {
|
||||
pname = "speexdsp-ns";
|
||||
version = "0.1.2";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "TeaPoly";
|
||||
repo = "speexdsp-ns-python";
|
||||
rev = "8af784a230e23f4eeaa4a58111774ad0864b1f0b";
|
||||
hash = "sha256-9IGhHZBlDYfGygB+fAdEDp7qeIEOWBsiLZAUFTVBxG0=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [swig];
|
||||
propagatedBuildInputs = [speexdsp];
|
||||
}
|
32
nixosModules/wyoming-plus/pkgs/wyoming-openwakeword.nix
Normal file
32
nixosModules/wyoming-plus/pkgs/wyoming-openwakeword.nix
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
This package uses a `wyoming-openwakeword` fork that makes use of
|
||||
the upstream `openwakeword` instead of a fork: https://github.com/rhasspy/wyoming-openwakeword/pull/27
|
||||
|
||||
It also enforces the python version to 3.11, because tensorflow
|
||||
cannot be used with 3.12 yet.
|
||||
*/
|
||||
pkgs: let
|
||||
pyPkgs = pkgs.python311Packages;
|
||||
|
||||
speexdsp-ns = pkgs.callPackage ./speexdsp-ns.nix {
|
||||
python3Packages = pyPkgs;
|
||||
};
|
||||
|
||||
openwakeword = pkgs.callPackage ./openwakeword.nix {
|
||||
inherit speexdsp-ns;
|
||||
python3Packages = pyPkgs;
|
||||
};
|
||||
in
|
||||
(pkgs.wyoming-openwakeword.override {
|
||||
python3Packages = pyPkgs;
|
||||
})
|
||||
.overrideAttrs (o: {
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "rhasspy";
|
||||
repo = "wyoming-openwakeword";
|
||||
rev = "synesthesiam-20240627-openwakeword";
|
||||
hash = "sha256-69oR2LHiUfx8j39nWp7XhG5xTvmOoPCLjSlH1CFvavo=";
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [openwakeword pyPkgs.wyoming];
|
||||
})
|
Loading…
Reference in a new issue