at 23.11-pre 4.4 kB view raw
1{ config 2, lib 3, pkgs 4, ... 5}: 6 7let 8 cfg = config.services.tts; 9in 10 11{ 12 options.services.tts = let 13 inherit (lib) literalExpression mkOption mdDoc mkEnableOption types; 14 in { 15 servers = mkOption { 16 type = types.attrsOf (types.submodule ( 17 { ... }: { 18 options = { 19 enable = mkEnableOption (mdDoc "Coqui TTS server"); 20 21 port = mkOption { 22 type = types.port; 23 example = 5000; 24 description = mdDoc '' 25 Port to bind the TTS server to. 26 ''; 27 }; 28 29 model = mkOption { 30 type = types.nullOr types.str; 31 default = "tts_models/en/ljspeech/tacotron2-DDC"; 32 example = null; 33 description = mdDoc '' 34 Name of the model to download and use for speech synthesis. 35 36 Check `tts-server --list_models` for possible values. 37 38 Set to `null` to use a custom model. 39 ''; 40 }; 41 42 useCuda = mkOption { 43 type = types.bool; 44 default = false; 45 example = true; 46 description = mdDoc '' 47 Whether to offload computation onto a CUDA compatible GPU. 48 ''; 49 }; 50 51 extraArgs = mkOption { 52 type = types.listOf types.str; 53 default = []; 54 description = mdDoc '' 55 Extra arguments to pass to the server commandline. 56 ''; 57 }; 58 }; 59 } 60 )); 61 default = {}; 62 example = literalExpression '' 63 { 64 english = { 65 port = 5300; 66 model = "tts_models/en/ljspeech/tacotron2-DDC"; 67 }; 68 german = { 69 port = 5301; 70 model = "tts_models/de/thorsten/tacotron2-DDC"; 71 }; 72 dutch = { 73 port = 5302; 74 model = "tts_models/nl/mai/tacotron2-DDC"; 75 }; 76 } 77 ''; 78 description = mdDoc '' 79 TTS server instances. 80 ''; 81 }; 82 }; 83 84 config = let 85 inherit (lib) mkIf mapAttrs' nameValuePair optionalString concatMapStringsSep escapeShellArgs; 86 in mkIf (cfg.servers != {}) { 87 systemd.services = mapAttrs' (server: options: 88 nameValuePair "tts-${server}" { 89 description = "Coqui TTS server instance ${server}"; 90 after = [ 91 "network-online.target" 92 ]; 93 wantedBy = [ 94 "multi-user.target" 95 ]; 96 path = with pkgs; [ 97 espeak-ng 98 ]; 99 environment.HOME = "/var/lib/tts"; 100 serviceConfig = { 101 DynamicUser = true; 102 User = "tts"; 103 StateDirectory = "tts"; 104 ExecStart = "${pkgs.tts}/bin/tts-server --port ${toString options.port}" 105 + optionalString (options.model != null) " --model_name ${options.model}" 106 + optionalString (options.useCuda) " --use_cuda" 107 + (concatMapStringsSep " " escapeShellArgs options.extraArgs); 108 CapabilityBoundingSet = ""; 109 DeviceAllow = if options.useCuda then [ 110 # https://docs.nvidia.com/dgx/pdf/dgx-os-5-user-guide.pdf 111 "/dev/nvidia1" 112 "/dev/nvidia2" 113 "/dev/nvidia3" 114 "/dev/nvidia4" 115 "/dev/nvidia-caps/nvidia-cap1" 116 "/dev/nvidia-caps/nvidia-cap2" 117 "/dev/nvidiactl" 118 "/dev/nvidia-modeset" 119 "/dev/nvidia-uvm" 120 "/dev/nvidia-uvm-tools" 121 ] else ""; 122 DevicePolicy = "closed"; 123 LockPersonality = true; 124 # jit via numba->llvmpipe 125 MemoryDenyWriteExecute = false; 126 PrivateDevices = true; 127 PrivateUsers = true; 128 ProtectHome = true; 129 ProtectHostname = true; 130 ProtectKernelLogs = true; 131 ProtectKernelModules = true; 132 ProtectKernelTunables = true; 133 ProtectControlGroups = true; 134 ProtectProc = "invisible"; 135 ProcSubset = "pid"; 136 RestrictAddressFamilies = [ 137 "AF_INET" 138 "AF_INET6" 139 ]; 140 RestrictNamespaces = true; 141 RestrictRealtime = true; 142 SystemCallArchitectures = "native"; 143 SystemCallFilter = [ 144 "@system-service" 145 "~@privileged" 146 ]; 147 UMask = "0077"; 148 }; 149 }) cfg.servers; 150 }; 151}