diff --git a/modules/home/services/numen/default.nix b/modules/home/services/numen/default.nix new file mode 100644 index 0000000..8cde203 --- /dev/null +++ b/modules/home/services/numen/default.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, ... }: +# Source: https://github.com/Lykos153/numen-nix +with lib; + +let + cfg = config.services.numen; +in +{ + options.services.numen = { + enable = mkOption { + type = types.bool; + default = false; + }; + + numenPkg = mkOption { + type = types.package; + default = pkgs.internal.numen; + }; + + # models = mkOption { + # type = types.uniq types.listOf types.package; + # default = [vosk-model-small-en-us]; + # example = "[vosk-model-small-en-us]"; + # description = '' + # List of vosk models to be loaded by numen. They can be referred to using the index, eg. model0 or model1. + # ''; + # }; + + model = mkOption { + type = types.pathInStore; + default = "${pkgs.internal.vosk-model-small-en-us}/usr/share/vosk-models/small-en-us/"; + example = "vosk-model-small-en-us"; + description = '' + Vosk model to be loaded by numen. + ''; + }; + + phrases = mkOption { + type = types.listOf types.path; + default = [ ]; + description = '' + Phrases to be loaded by numen. If empty, the default phrases are used. + ''; + }; + + extraArgs = mkOption { + type = types.singleLineStr; + default = ""; + description = '' + Additional arguments to be passed to numen. + ''; + }; + + dotoolXkbLayout = mkOption { + type = types.singleLineStr; + default = "en"; + description = '' + The XKB keyboard layout that should be used by dotool. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.numen = { + Unit = { + Description = "Numen voice control"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + Install.WantedBy = [ "graphical-session.target" ]; + Service.Environment = [ + "DOTOOL_XKB_LAYOUT=${cfg.dotoolXkbLayout}" + "NUMEN_MODEL=${cfg.model}" + ]; + Service.ExecStart = "${cfg.numenPkg}/bin/numen ${cfg.extraArgs} ${lib.strings.concatStringsSep " " cfg.phrases}"; + }; + }; +} diff --git a/packages/dotool/default.nix b/packages/dotool/default.nix new file mode 100644 index 0000000..e7d4e5f --- /dev/null +++ b/packages/dotool/default.nix @@ -0,0 +1,18 @@ +{ fetchFromSourcehut, buildGoModule, pkg-config, libxkbcommon, tree }: +# Source: https://github.com/Lykos153/numen-nix +buildGoModule rec { + pname = "dotool"; + version = "1.5"; + src = fetchFromSourcehut { + owner = "~geb"; + repo = pname; + rev = version; + hash = "sha256-4QmTHeU3TnpRATKIvilkIA3i2hDjM5zQwSvmRvoWuNE="; + }; + vendorHash = "sha256-IQ847LHDYJPboWL/6lQNJ4vPPD/+xkrGI2LSZ7kBnp4="; + nativeBuildInputs = [ pkg-config tree ]; + buildInputs = [ libxkbcommon ]; + postInstall = '' + install -D $src/80-dotool.rules $out/lib/udev/rules.d/80-dotool.rules + ''; +} diff --git a/packages/intel-media-sdk/default.nix b/packages/intel-media-sdk/default.nix new file mode 100644 index 0000000..4898edf --- /dev/null +++ b/packages/intel-media-sdk/default.nix @@ -0,0 +1,66 @@ +{ + lib, + stdenv, + fetchFromGitHub, + cmake, + pkgs, + ... +}: + +stdenv.mkDerivation rec { + pname = "intel-media-sdk"; + version = "23.2.2"; + + src = fetchFromGitHub { + owner = "Intel-Media-SDK"; + repo = "MediaSDK"; + rev = "intel-mediasdk-${version}"; + hash = "sha256-wno3a/ZSKvgHvZiiJ0Gq9GlrEbfHCizkrSiHD6k/Loo="; + }; + + patches = [ + # Search oneVPL-intel-gpu in NixOS specific /run/opengl-driver/lib directory + # See https://github.com/NixOS/nixpkgs/pull/315425 + ./nixos-search-onevplrt-in-run-opengl-driver-lib.patch + # https://github.com/Intel-Media-SDK/MediaSDK/pull/3005 + (pkgs.fetchpatch { + name = "include-cstdint-explicitly.patch"; + url = "https://github.com/Intel-Media-SDK/MediaSDK/commit/a4f37707c1bfdd5612d3de4623ffb2d21e8c1356.patch"; + hash = "sha256-OPwGzcMTctJvHcKn5bHqV8Ivj4P7+E4K9WOKgECqf04="; + }) + ]; + + nativeBuildInputs = [ + pkgs.cmake + pkgs.pkg-config + ]; + buildInputs = [ + pkgs.libdrm + pkgs.libva + pkgs.xorg.libpciaccess + pkgs.xorg.libX11 + pkgs.xorg.libXau + pkgs.xorg.libXdmcp + pkgs.xorg.libpthreadstubs + ]; + nativeCheckInputs = [ pkgs.gtest ]; + + cmakeFlags = [ + "-DBUILD_SAMPLES=OFF" + "-DBUILD_TESTS=${if doCheck then "ON" else "OFF"}" + "-DUSE_SYSTEM_GTEST=ON" + ]; + + doCheck = true; + + meta = with lib; { + description = "Intel Media SDK"; + mainProgram = "mfx-tracer-config"; + license = licenses.mit; + maintainers = with maintainers; [ + midchildan + pjungkamp + ]; + platforms = [ "x86_64-linux" "i686-linux" ]; + }; +} diff --git a/packages/intel-media-sdk/nixos-search-onevplrt-in-run-opengl-driver-lib.patch b/packages/intel-media-sdk/nixos-search-onevplrt-in-run-opengl-driver-lib.patch new file mode 100644 index 0000000..5057de1 --- /dev/null +++ b/packages/intel-media-sdk/nixos-search-onevplrt-in-run-opengl-driver-lib.patch @@ -0,0 +1,45 @@ +From aceb689ae69857def8a26a8d1ceb114ccfbb2569 Mon Sep 17 00:00:00 2001 +From: Philipp Jungkamp +Date: Tue, 28 May 2024 19:22:29 +0200 +Subject: [PATCH] NixOS: Search ONEVPLRT in /run/opengl-driver/lib + +--- + api/mfx_dispatch/linux/mfxloader.cpp | 2 ++ + .../suites/mfx_dispatch/linux/mfx_dispatch_test_cases_libs.cpp | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/api/mfx_dispatch/linux/mfxloader.cpp b/api/mfx_dispatch/linux/mfxloader.cpp +index 39b6bff1..f76ed65d 100644 +--- a/api/mfx_dispatch/linux/mfxloader.cpp ++++ b/api/mfx_dispatch/linux/mfxloader.cpp +@@ -193,6 +193,7 @@ mfxStatus LoaderCtx::Init(mfxInitParam& par) + if (selected_runtime && strcmp(selected_runtime, "ONEVPL") == 0) { + libs.emplace_back(ONEVPLRT); + libs.emplace_back(MFX_MODULES_DIR "/" ONEVPLRT); ++ libs.emplace_back("/run/opengl-driver/lib/" ONEVPLRT); + } else if ((selected_runtime && strcmp(selected_runtime, "MSDK") == 0) || (platform != MFX_HW_UNKNOWN)) { + if (MFX_IMPL_BASETYPE(par.Implementation) == MFX_IMPL_AUTO || + MFX_IMPL_BASETYPE(par.Implementation) == MFX_IMPL_AUTO_ANY) { +@@ -213,6 +214,7 @@ mfxStatus LoaderCtx::Init(mfxInitParam& par) + } else { + libs.emplace_back(ONEVPLRT); + libs.emplace_back(MFX_MODULES_DIR "/" ONEVPLRT); ++ libs.emplace_back("/run/opengl-driver/lib/" ONEVPLRT); + } + + mfxStatus mfx_res = MFX_ERR_UNSUPPORTED; +diff --git a/tests/unit/suites/mfx_dispatch/linux/mfx_dispatch_test_cases_libs.cpp b/tests/unit/suites/mfx_dispatch/linux/mfx_dispatch_test_cases_libs.cpp +index dedee0b3..9657da4b 100644 +--- a/tests/unit/suites/mfx_dispatch/linux/mfx_dispatch_test_cases_libs.cpp ++++ b/tests/unit/suites/mfx_dispatch/linux/mfx_dispatch_test_cases_libs.cpp +@@ -123,6 +123,7 @@ TEST_P(DispatcherLibsTestParametrized, ShouldEnumerateCorrectLibNames) + { + libs.emplace_back(ONEVPLRT); + libs.emplace_back(modules_dir + "/" + ONEVPLRT); ++ libs.emplace_back("/run/opengl-driver/lib/" + ONEVPLRT); + } + + for (const std::string& lib : libs) +-- +2.44.0 + diff --git a/packages/numen/default.nix b/packages/numen/default.nix new file mode 100644 index 0000000..b3ab5a0 --- /dev/null +++ b/packages/numen/default.nix @@ -0,0 +1,88 @@ +{ fetchFromSourcehut +, stdenv +, buildGoModule +, makeWrapper +, scdoc +, pkgs +, lib +, alsa-utils +, libxkbcommon +, gnused +, gawk +, coreutils +, libnotify +, dmenu +, procps +}: +# Source: https://github.com/Lykos153/numen-nix +buildGoModule rec { + pname = "numen"; + version = "master"; + vendorHash = "sha256-Y3CbAnIK+gEcUfll9IlEGZE/s3wxdhAmTJkj9zlAtoQ="; + src = fetchFromSourcehut { + owner = "~geb"; + repo = pname; + rev = version; + hash = "sha256-haiaMBq9xbcDd83Kmm00Xc7823U+90DworOZk9H2n9w="; + }; + + allowGoReference = true; + preBuild = '' + export CGO_CFLAGS="-I${pkgs.internal.vosk-bin}/include" + export CGO_LDFLAGS="-L${pkgs.internal.vosk-bin}/lib" + ''; + nativeBuildInputs = [ + makeWrapper + scdoc + ]; + ldflags = [ + "-X main.Version=${version}" + "-X main.DefaultModelPackage=vosk-model-small-en-us" + "-X main.DefaultModelPaths=${pkgs.internal.vosk-model-small-en-us}/usr/share/vosk-models/small-en-us" + "-X main.DefaultPhrasesDir=${placeholder "out"}/etc/numen/phrases" + ]; + # This is necessary because while the scripts are copied relative to + # the nix store, the hard-coded paths inside the scripts themselves + # still point outside of the store. + patchPhase = '' + substituteInPlace scripts/* \ + --replace /etc/numen/scripts "$out/etc/numen/scripts" \ + --replace sed ${gnused}/bin/sed \ + --replace awk ${gawk}/bin/awk \ + --replace cat ${coreutils}/bin/cat \ + --replace notify-send ${libnotify}/bin/notify-send + substituteInPlace scripts/menu \ + --replace "-dmenu" "-${dmenu}/bin/dmenu" + substituteInPlace scripts/displaying \ + --replace "(pgrep" "(${procps}/bin/pgrep" \ + --replace "(ps" "(${procps}/bin/ps" + substituteInPlace phrases/* \ + --replace /etc/numen/scripts "$out/etc/numen/scripts" \ + --replace numenc "$out/bin/numenc" + substituteInPlace numenc \ + --replace /bin/echo "${coreutils}/bin/echo" \ + --replace cat "${coreutils}/bin/cat" + ''; + installPhase = '' + runHook preInstall + + install -Dm755 $GOPATH/bin/numen -t "$out/bin" + install -Dm755 numenc -t "$out/bin" + install -Dm755 scripts/* -t "$out/scripts" + install -Dm644 phrases/* -t "$out/prases" + sed -i "s:/etc/numen/scripts:${placeholder "out"}/scripts:g" \ + $out/scripts/* \ + $out/prases/* + mkdir -p "$out/usr/share/man/man1" || exit + scdoc < doc/numen.1.scd > "$out/usr/share/man/man1/numen.1" || exit + echo Installed Successfully. + + + runHook postInstall + ''; + postFixup = '' + wrapProgram $out/bin/numen \ + --prefix PATH : ${lib.makeBinPath [ pkgs.internal.dotool alsa-utils ]} \ + --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ libxkbcommon stdenv.cc.cc.lib ]} \ + ''; +} diff --git a/packages/vosk-bin/default.nix b/packages/vosk-bin/default.nix new file mode 100644 index 0000000..f2de716 --- /dev/null +++ b/packages/vosk-bin/default.nix @@ -0,0 +1,40 @@ +{ stdenv, fetchurl, unzip, system }: +# Source https://github.com/Lykos153/numen-nix +let + getSource = system: version: let + sources = { + x86_64-linux = { + systemString = "linux-x86_64"; + sha256 = "sha256-u9yO2FxDl59kQxQoiXcOqVy/vFbP+1xdzXOvqHXF+7I="; + }; + aarch64-linux = { + systemString = "linux-aarch64"; + sha256 = "sha256-ReldN3Vd6wdWjnlJfX/rqMA67lqeBx3ymWGqAj/ZRUE="; + }; + i686-linux = { + systemString = "linux-x86"; + sha256 = "sha256-tTnvwieAlIvZji7LnBuSygizxVKhh0T3ICq3hAW44fk="; + }; + }; + in { + url = "https://github.com/alphacep/vosk-api/releases/download/v${version}/vosk-${(builtins.getAttr system sources).systemString}-${version}.zip"; + sha256 = (builtins.getAttr system sources).sha256; + + }; +in +stdenv.mkDerivation rec { + # todo: other arches as well. + name = "vosk-bin"; + version = "0.3.45"; + src = fetchurl (getSource system version); + nativeBuildInputs = [ unzip ]; + unpackCmd = "unzip $curSrc"; + + installPhase = '' + mkdir -p $out/lib + mv libvosk.so $out/lib/ + mkdir -p $out/include + mv vosk_api.h $out/include/ + ''; +} + diff --git a/packages/vosk-model-small-en-us/default.nix b/packages/vosk-model-small-en-us/default.nix new file mode 100644 index 0000000..ff4a850 --- /dev/null +++ b/packages/vosk-model-small-en-us/default.nix @@ -0,0 +1,18 @@ +{ stdenv, fetchurl, unzip }: +# Source: https://github.com/Lykos153/numen-nix +stdenv.mkDerivation { + name = "vosk-model-small-en-us"; + version = "0.15"; + src = fetchurl { + url = + "https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.15.zip"; + sha256 = "sha256-MPJiQsTrRJ+UjkLLMC3XpobLKaNCOoNn+Z/0F4CUJJg="; + }; + nativeBuildInputs = [ unzip ]; + unpackCmd = "unzip $curSrc"; + + installPhase = '' + mkdir -p $out/usr/share/vosk-models + cp -r . $out/usr/share/vosk-models/small-en-us + ''; +}