Unverified Commit 0663b90f authored by Martin Weinelt's avatar Martin Weinelt Committed by GitHub
Browse files

Merge pull request #213232 from mweinelt/tts-module

nixos/tts: init
parents a4679a5a 6f0616b5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ In addition to numerous new and upgraded packages, this release has the followin

- [goeland](https://github.com/slurdge/goeland), an alternative to rss2email written in golang with many filters. Available as [services.goeland](#opt-services.goeland.enable).

- [tts](https://github.com/coqui-ai/TTS), a battle-tested deep learning toolkit for Text-to-Speech. Mutiple servers may be configured below [services.tts.servers](#opt-services.tts.servers).

- [atuin](https://github.com/ellie/atuin), a sync server for shell history. Available as [services.atuin](#opt-services.atuin.enable).

- [networkd-dispatcher](https://gitlab.com/craftyguy/networkd-dispatcher), a dispatcher service for systemd-networkd connection status changes. Available as [services.networkd-dispatcher](#opt-services.networkd-dispatcher.enable).
+1 −0
Original line number Diff line number Diff line
@@ -314,6 +314,7 @@
  ./services/audio/snapserver.nix
  ./services/audio/spotifyd.nix
  ./services/audio/squeezelite.nix
  ./services/audio/tts.nix
  ./services/audio/ympd.nix
  ./services/backup/automysqlbackup.nix
  ./services/backup/bacula.nix
+151 −0
Original line number Diff line number Diff line
{ config
, lib
, pkgs
, ...
}:

let
  cfg = config.services.tts;
in

{
  options.services.tts = let
    inherit (lib) literalExpression mkOption mdDoc mkEnableOption types;
  in  {
    servers = mkOption {
      type = types.attrsOf (types.submodule (
        { ... }: {
          options = {
            enable = mkEnableOption (mdDoc "Coqui TTS server");

            port = mkOption {
              type = types.port;
              example = 5000;
              description = mdDoc ''
                Port to bind the TTS server to.
              '';
            };

            model = mkOption {
              type = types.nullOr types.str;
              default = "tts_models/en/ljspeech/tacotron2-DDC";
              example = null;
              description = mdDoc ''
                Name of the model to download and use for speech synthesis.

                Check `tts-server --list_models` for possible values.

                Set to `null` to use a custom model.
              '';
            };

            useCuda = mkOption {
              type = types.bool;
              default = false;
              example = true;
              description = mdDoc ''
                Whether to offload computation onto a CUDA compatible GPU.
              '';
            };

            extraArgs = mkOption {
              type = types.listOf types.str;
              default = [];
              description = mdDoc ''
                Extra arguments to pass to the server commandline.
              '';
            };
          };
        }
      ));
      default = {};
      example = literalExpression ''
        {
          english = {
            port = 5300;
            model = "tts_models/en/ljspeech/tacotron2-DDC";
          };
          german = {
            port = 5301;
            model = "tts_models/de/thorsten/tacotron2-DDC";
          };
          dutch = {
            port = 5302;
            model = "tts_models/nl/mai/tacotron2-DDC";
          };
        }
      '';
      description = mdDoc ''
        TTS server instances.
      '';
    };
  };

  config = let
    inherit (lib) mkIf mapAttrs' nameValuePair optionalString concatMapStringsSep escapeShellArgs;
  in mkIf (cfg.servers != {}) {
    systemd.services = mapAttrs' (server: options:
      nameValuePair "tts-${server}" {
        description = "Coqui TTS server instance ${server}";
        after = [
          "network-online.target"
        ];
        wantedBy = [
          "multi-user.target"
        ];
        path = with pkgs; [
          espeak-ng
        ];
        environment.HOME = "/var/lib/tts";
        serviceConfig = {
          DynamicUser = true;
          User = "tts";
          StateDirectory = "tts";
          ExecStart = "${pkgs.tts}/bin/tts-server --port ${toString options.port}"
            + optionalString (options.model != null) " --model_name ${options.model}"
            + optionalString (options.useCuda) " --use_cuda"
            + (concatMapStringsSep " " escapeShellArgs options.extraArgs);
          CapabilityBoundingSet = "";
          DeviceAllow = if options.useCuda then [
            # https://docs.nvidia.com/dgx/pdf/dgx-os-5-user-guide.pdf
            "/dev/nvidia1"
            "/dev/nvidia2"
            "/dev/nvidia3"
            "/dev/nvidia4"
            "/dev/nvidia-caps/nvidia-cap1"
            "/dev/nvidia-caps/nvidia-cap2"
            "/dev/nvidiactl"
            "/dev/nvidia-modeset"
            "/dev/nvidia-uvm"
            "/dev/nvidia-uvm-tools"
          ] else "";
          DevicePolicy = "closed";
          LockPersonality = true;
          # jit via numba->llvmpipe
          MemoryDenyWriteExecute = false;
          PrivateDevices = true;
          PrivateUsers = true;
          ProtectHome = true;
          ProtectHostname = true;
          ProtectKernelLogs = true;
          ProtectKernelModules = true;
          ProtectKernelTunables = true;
          ProtectControlGroups = true;
          ProtectProc = "invisible";
          ProcSubset = "pid";
          RestrictAddressFamilies = [
            "AF_INET"
            "AF_INET6"
          ];
          RestrictNamespaces = true;
          RestrictRealtime = true;
          SystemCallArchitectures = "native";
          SystemCallFilter = [
            "@system-service"
            "~@privileged"
          ];
          UMask = "0077";
        };
      }) cfg.servers;
  };
}
+0 −10
Original line number Diff line number Diff line
@@ -5,16 +5,6 @@
, espeak-ng
}:

# USAGE:
# $ tts-server --list_models
# # pick your favorite vocoder/tts model
# $ tts-server --model_name tts_models/en/ljspeech/glow-tts --vocoder_name vocoder_models/universal/libri-tts/fullband-melgan
#
# If you upgrade from an old version you may have to delete old models from ~/.local/share/tts
#
# For now, for deployment check the systemd unit in the pull request:
#   https://github.com/NixOS/nixpkgs/pull/103851#issue-521121136

let
  python = python3.override {
    packageOverrides = self: super: {