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