From 7e65dfde31eae46cce35daf2d92ecf1ee784b285 Mon Sep 17 00:00:00 2001 From: Adrian G L Date: Tue, 24 Mar 2026 13:52:34 +0100 Subject: [PATCH] feat: tts :q --- flake.nix | 25 +++++-- modules/llama-swap.nix | 16 +++++ modules/python-packages.nix | 1 + packages/fish-speech-models/default.nix | 89 +++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 packages/fish-speech-models/default.nix diff --git a/flake.nix b/flake.nix index 84a8481..85624bf 100644 --- a/flake.nix +++ b/flake.nix @@ -62,12 +62,25 @@ system = "x86_64-linux"; in { - packages.${system} = { - qwen-asr = nixpkgs.legacyPackages.${system}.callPackage ./packages/qwen-asr.nix { }; - llama-swap = nixpkgs.legacyPackages.${system}.callPackage ./packages/llama-swap { }; - z-image-models = nixpkgs.legacyPackages.${system}.callPackage ./packages/z-image-models { }; - whisper-models = nixpkgs.legacyPackages.${system}.callPackage ./packages/whisper-models { }; - }; + packages.${system} = + let + lib = nixpkgs.lib; + pkgs = import nixpkgs { + inherit system; + config.allowUnfreePredicate = + pkg: + builtins.elem (lib.getName pkg) [ + "fish-speech-models" + ]; + }; + in + { + qwen-asr = pkgs.callPackage ./packages/qwen-asr.nix { }; + llama-swap = pkgs.callPackage ./packages/llama-swap { }; + z-image-models = pkgs.callPackage ./packages/z-image-models { }; + whisper-models = pkgs.callPackage ./packages/whisper-models { }; + fish-speech-models = pkgs.callPackage ./packages/fish-speech-models { }; + }; # legolas nixosConfigurations.legolas = nixpkgs.lib.nixosSystem { diff --git a/modules/llama-swap.nix b/modules/llama-swap.nix index c7e8323..7f56bba 100644 --- a/modules/llama-swap.nix +++ b/modules/llama-swap.nix @@ -7,12 +7,14 @@ ... }: { + environment.systemPackages = [ pkgs.unstable.llama-cpp-vulkan pkgs.unstable.stable-diffusion-cpp-vulkan pkgs.unstable.whisper-cpp-vulkan inputs.self.packages.${system}.z-image-models inputs.self.packages.${system}.whisper-models + inputs.self.packages.${system}.fish-speech-models ]; services.llama-swap = { @@ -28,6 +30,7 @@ whisper-server = lib.getExe' pkgs.unstable.whisper-cpp-vulkan "whisper-server"; z-image-models = inputs.self.packages.${system}.z-image-models; whisper-models = inputs.self.packages.${system}.whisper-models; + fish-speech-models = inputs.self.packages.${system}.fish-speech-models; in { healthCheckTimeout = 180; @@ -125,6 +128,19 @@ ]; macros.model = "${whisper-models}/models/nb-whisper-small-q5_0.bin"; }; + "fish-speech-s2-pro" = { + cmd = "docker run --rm --name fish-speech-$\{PORT\} -p $\{PORT\}:8080 -v $\{models\}/s2-pro:/app/checkpoints/s2-pro:ro fishaudio/fish-speech:server-cpu"; + cmdStop = "docker stop fish-speech-$\{PORT\}"; + checkEndpoint = "/v1/health"; + proxy = "http://127.0.0.1:$\{PORT\}"; + ttl = 0; + aliases = [ + "tts-1" + "tts" + "fish-speech" + ]; + macros.models = "${fish-speech-models}/models"; + }; }; }; }; diff --git a/modules/python-packages.nix b/modules/python-packages.nix index 2c86ce7..fa601c8 100644 --- a/modules/python-packages.nix +++ b/modules/python-packages.nix @@ -6,6 +6,7 @@ ps: with ps; [ numpy scipy pandas + polars matplotlib seaborn scikit-learn diff --git a/packages/fish-speech-models/default.nix b/packages/fish-speech-models/default.nix new file mode 100644 index 0000000..d440cd3 --- /dev/null +++ b/packages/fish-speech-models/default.nix @@ -0,0 +1,89 @@ +{ + lib, + fetchurl, + runCommand, +}: + +let + model1 = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/model-00001-of-00002.safetensors"; + hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + name = "model-00001-of-00002.safetensors"; + }; + + model2 = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/model-00002-of-00002.safetensors"; + hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + name = "model-00002-of-00002.safetensors"; + }; + + codec = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/codec.pth"; + hash = "sha256-dPxBxacVHG81Cvi9fl1uOsz8x/Pfv6wjr9Na8HBSuy8="; + name = "codec.pth"; + }; + + config = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/config.json"; + hash = "sha256-JhtRmiqVdnEPyFM6dyl/rgB/Dns6ooohf4NSt/Mv6ZM="; + name = "config.json"; + }; + + tokenizer = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/tokenizer.json"; + hash = "sha256-8k4ICZ1FqK3z9S9fCwMnbkM7udaJuxX8vMSM5YdEWIs="; + name = "tokenizer.json"; + }; + + tokenizerConfig = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/tokenizer_config.json"; + hash = "sha256-uNFJNDrkJbDaZ+Zwhoas61G+eBXZeS8mX8Ev8E1emFY="; + name = "tokenizer_config.json"; + }; + + specialTokensMap = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/special_tokens_map.json"; + hash = "sha256-wv8Y/ebkO3QIQ1vI7Qea90UxvvulSTWKl8vFnOYGvGs="; + name = "special_tokens_map.json"; + }; + + chatTemplate = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/chat_template.jinja"; + hash = "sha256-h6JyjLjcn+Qk1iRUL2Bg7AWh0oXrvsV4uweJAOMzlrU="; + name = "chat_template.jinja"; + }; + + modelIndex = fetchurl { + url = "https://huggingface.co/fishaudio/s2-pro/resolve/main/model.safetensors.index.json"; + hash = "sha256-yMuZdNPRdmOpXbodbD6lMfxC03fA3/lG86AaDsSNRaM="; + name = "model.safetensors.index.json"; + }; +in +runCommand "fish-speech-models" + { + version = "1.0.0"; + meta = { + description = "Fish Audio S2 Pro TTS model"; + homepage = "https://huggingface.co/fishaudio/s2-pro"; + license = { + shortName = "fish-audio-research"; + fullName = "Fish Audio Research License"; + url = "https://huggingface.co/fishaudio/s2-pro/blob/main/LICENSE.md"; + free = false; + redistributable = true; + }; + platforms = lib.platforms.all; + }; + } + '' + mkdir -p $out/models/s2-pro + ln -s ${model1} $out/models/s2-pro/model-00001-of-00002.safetensors + ln -s ${model2} $out/models/s2-pro/model-00002-of-00002.safetensors + ln -s ${codec} $out/models/s2-pro/codec.pth + ln -s ${config} $out/models/s2-pro/config.json + ln -s ${tokenizer} $out/models/s2-pro/tokenizer.json + ln -s ${tokenizerConfig} $out/models/s2-pro/tokenizer_config.json + ln -s ${specialTokensMap} $out/models/s2-pro/special_tokens_map.json + ln -s ${chatTemplate} $out/models/s2-pro/chat_template.jinja + ln -s ${modelIndex} $out/models/s2-pro/model.safetensors.index.json + ''