KittenTTS 0.8.1 requires misaki[en]>=0.9.4, and PyPI's misaki 0.9.4 declares requires-python <3.13, so the extra was gated off the managed 3.14 interpreter. NousResearch/misaki f03fd2be73 is upstream main (0.9.4 + "Enable Python 3.13") with the cap raised to <3.15 and no code change. The extra now declares misaki[en] at that commit directly, so uv resolves KittenTTS's transitive requirement to the fork. A [tool.uv.sources] entry would not reach a transitive dependency, and an override would bypass pip installs of the extra. The extra is gated on platform instead of Python: onnxruntime has no Intel macOS wheel and torch (pulled by misaki[en]) has no Windows ARM64 wheel, the same gate piper already carries. Nix: uv.lock records no build backend for the git source, so buildSystemOverrides supplies hatchling for misaki. Without it the opt-in build fails with "No module named 'hatchling'". The default package derivation is unchanged; kittentts is in no Nix bundle. Verified on macOS arm64 with CPython 3.14.7: uv sync --frozen --extra kittentts from this lock installs misaki from the fork commit, and tools.tts_tool_local._generate_kittentts writes a 3.87 s 24 kHz WAV.
182 lines
5.7 KiB
Nix
182 lines
5.7 KiB
Nix
# nix/python.nix — uv2nix virtual environment builder
|
|
{
|
|
lib,
|
|
callPackage,
|
|
uv2nix,
|
|
pyproject-nix,
|
|
pyproject-build-systems,
|
|
stdenv,
|
|
# Filtered Python source (see lib.nix pythonSrc) — keeps JS/docs/skills
|
|
# edits from invalidating the venv derivation.
|
|
pythonSrc,
|
|
dependency-groups ? [ "all" ],
|
|
}:
|
|
let
|
|
# The interpreter family comes from pm/lock.json (pythonLock.nix owns the
|
|
# selection); every override below must be built for THAT interpreter.
|
|
pythonLock = callPackage ./pythonLock.nix { };
|
|
python = pythonLock.interpreter;
|
|
pythonPackages = python.pkgs;
|
|
|
|
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = pythonSrc; };
|
|
hacks = callPackage pyproject-nix.build.hacks { };
|
|
|
|
overlay = workspace.mkPyprojectOverlay {
|
|
sourcePreference = "wheel";
|
|
};
|
|
|
|
isAarch64Darwin = stdenv.hostPlatform.system == "aarch64-darwin";
|
|
|
|
# Keep the workspace locked through uv2nix, but supply the local voice stack
|
|
# from nixpkgs so wheel-only transitive artifacts do not break evaluation.
|
|
mkPrebuiltPassthru = dependencies: {
|
|
inherit dependencies;
|
|
optional-dependencies = { };
|
|
dependency-groups = { };
|
|
};
|
|
|
|
mkPrebuiltOverride =
|
|
final: from: dependencies:
|
|
hacks.nixpkgsPrebuilt {
|
|
inherit from;
|
|
prev = {
|
|
nativeBuildInputs = [ final.pyprojectHook ];
|
|
passthru = mkPrebuiltPassthru dependencies;
|
|
};
|
|
};
|
|
|
|
# Legacy alibabacloud packages ship only sdists with setup.py/setup.cfg
|
|
# and no pyproject.toml, so setuptools isn't declared as a build dep.
|
|
buildSystemOverrides =
|
|
final: prev:
|
|
builtins.mapAttrs
|
|
(
|
|
name: _:
|
|
prev.${name}.overrideAttrs (old: {
|
|
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ final.setuptools ];
|
|
})
|
|
)
|
|
(
|
|
lib.genAttrs [
|
|
"alibabacloud-credentials-api"
|
|
"alibabacloud-endpoint-util"
|
|
"alibabacloud-gateway-dingtalk"
|
|
"alibabacloud-gateway-spi"
|
|
"alibabacloud-tea"
|
|
] (_: null)
|
|
)
|
|
// {
|
|
# The locked sdist has no build-system metadata; setup.py imports
|
|
# setuptools and uses CFFI to compile the bundled libolm.
|
|
python-olm = prev.python-olm.overrideAttrs (old: {
|
|
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ final.resolveBuildSystem {
|
|
setuptools = [ ];
|
|
cffi = [ ];
|
|
};
|
|
});
|
|
# [kittentts] locks misaki as a git source. uv.lock records no build
|
|
# backend for it, so supply the hatchling its pyproject declares.
|
|
misaki = prev.misaki.overrideAttrs (old: {
|
|
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ final.resolveBuildSystem {
|
|
hatchling = [ ];
|
|
};
|
|
});
|
|
};
|
|
|
|
pythonPackageOverrides =
|
|
final: _prev:
|
|
if isAarch64Darwin then
|
|
{
|
|
numpy = mkPrebuiltOverride final pythonPackages.numpy { };
|
|
|
|
pyarrow = mkPrebuiltOverride final pythonPackages.pyarrow { };
|
|
|
|
av = mkPrebuiltOverride final pythonPackages.av { };
|
|
|
|
humanfriendly = mkPrebuiltOverride final pythonPackages.humanfriendly { };
|
|
|
|
coloredlogs = mkPrebuiltOverride final pythonPackages.coloredlogs {
|
|
humanfriendly = [ ];
|
|
};
|
|
|
|
onnxruntime = mkPrebuiltOverride final pythonPackages.onnxruntime {
|
|
coloredlogs = [ ];
|
|
numpy = [ ];
|
|
packaging = [ ];
|
|
};
|
|
|
|
ctranslate2 = mkPrebuiltOverride final pythonPackages.ctranslate2 {
|
|
numpy = [ ];
|
|
pyyaml = [ ];
|
|
};
|
|
|
|
faster-whisper = mkPrebuiltOverride final pythonPackages.faster-whisper {
|
|
av = [ ];
|
|
ctranslate2 = [ ];
|
|
huggingface-hub = [ ];
|
|
onnxruntime = [ ];
|
|
tokenizers = [ ];
|
|
tqdm = [ ];
|
|
};
|
|
}
|
|
else
|
|
{ };
|
|
|
|
pythonSet =
|
|
(callPackage pyproject-nix.build.packages {
|
|
inherit python;
|
|
}).overrideScope
|
|
(
|
|
lib.composeManyExtensions [
|
|
pyproject-build-systems.overlays.default
|
|
overlay
|
|
buildSystemOverrides
|
|
pythonPackageOverrides
|
|
# ``setup.py`` permits wheel/sdist creation only from the sealed
|
|
# Hermes derivation. This is deliberately a derivation environment
|
|
# variable, not a devShell variable: ``nix develop -c uv build``
|
|
# must remain blocked.
|
|
(final: prev: {
|
|
hermes-agent = prev.hermes-agent.overrideAttrs (_old: {
|
|
HERMES_NIX_BUILD = "1";
|
|
});
|
|
})
|
|
]
|
|
);
|
|
|
|
# The editable venv points at the live checkout, so it uses an
|
|
# UNFILTERED workspace rooted at a real path — mkEditablePyprojectOverlay
|
|
# computes relative paths via lib.path.splitRoot, which rejects the
|
|
# filtered pythonSrc (a cleanSourceWith set, not a path). Filtering
|
|
# buys nothing here anyway: the editable install reads from
|
|
# $HERMES_PYTHON_SRC_ROOT at runtime.
|
|
workspaceRoot = ./..;
|
|
editableWorkspace = uv2nix.lib.workspace.loadWorkspace { inherit workspaceRoot; };
|
|
editableOverlay = editableWorkspace.mkEditablePyprojectOverlay {
|
|
root = "$HERMES_PYTHON_SRC_ROOT"; # resolved at shellHook time
|
|
};
|
|
|
|
editableSet = pythonSet.overrideScope (
|
|
lib.composeManyExtensions [
|
|
editableOverlay
|
|
(final: prev: {
|
|
hermes-agent = prev.hermes-agent.overrideAttrs (old: {
|
|
# point straight at the real source instead of the filtered nix store copy
|
|
src = workspaceRoot;
|
|
nativeBuildInputs = old.nativeBuildInputs ++ final.resolveBuildSystem { editables = [ ]; };
|
|
});
|
|
})
|
|
]
|
|
);
|
|
in
|
|
{
|
|
inherit python;
|
|
|
|
venv = pythonSet.mkVirtualEnv "hermes-agent-env" {
|
|
hermes-agent = dependency-groups;
|
|
};
|
|
editableVenv = editableSet.mkVirtualEnv "hermes-agent-editable-env" {
|
|
hermes-agent = dependency-groups;
|
|
};
|
|
}
|