feat(nix): add flake package, NixOS and Home Manager modules (#936)
* feat(nix): add flake package, NixOS and Home Manager modules Add a flake.nix plus packaging/nix derivations so Nix and NixOS users can run and install Vocalinux declaratively, including via Home Manager. - package.nix: buildPythonApplication with GTK3, libayatana-appindicator, IBus and libnotify typelibs; wraps the entry point with every host tool the injectors probe for (xdotool, wtype, ydotool, wl-clipboard, xclip, xsel, xprop, setxkbmap, ibus, gdbus, notify-send, paplay, aplay) - pywhispercpp.nix: builds pywhispercpp from its vendored PyPI sdist (absent from nixpkgs, same gap as Debian/Fedora), static whisper.cpp, GGML_NATIVE=OFF for a portable baseline - module.nix: NixOS module enabling hardware.uinput and installing the package; input/uinput group membership stays a per-user choice - home-manager.nix: programs.vocalinux.enable installs into the profile - docs/INSTALL.md gains a Nix / NixOS section; packaging/nix/README.md carries the usage snippets Refs #931 * fix(nix): address review findings on imports check and docs - pywhispercpp: check pywhispercpp.model and _pywhispercpp too, so the compiled binding is proven loadable, not just the package - README Home Manager example: declare the nixpkgs/home-manager inputs and pass pkgs, which homeManagerConfiguration requires - package.nix: use top-level xprop/setxkbmap attrs (xorg.* is deprecated) --------- Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
This commit is contained in:
co-authored by
Jatin K Malik
parent
5e97773ebb
commit
c3c390f19d
@@ -172,3 +172,7 @@ opentree.toml
|
|||||||
|
|
||||||
# Sisyphus - local AI agent loop state (per-developer, not shared)
|
# Sisyphus - local AI agent loop state (per-developer, not shared)
|
||||||
.sisyphus/
|
.sisyphus/
|
||||||
|
|
||||||
|
# Nix build output symlinks
|
||||||
|
result
|
||||||
|
result-*
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ How to install Vocalinux on Linux. Short overview: [project README](../README.md
|
|||||||
| [AUR](#arch-linux-aur) | Arch / Manjaro |
|
| [AUR](#arch-linux-aur) | Arch / Manjaro |
|
||||||
| [Flatpak](#flatpak) | Release `.flatpak` or local build |
|
| [Flatpak](#flatpak) | Release `.flatpak` or local build |
|
||||||
| [Snap](#snap-ubuntu-snap-store) | Ubuntu Snap Store (`--edge`) or GitHub `.snap` |
|
| [Snap](#snap-ubuntu-snap-store) | Ubuntu Snap Store (`--edge`) or GitHub `.snap` |
|
||||||
|
| [Nix](#nix--nixos) | Flake package, Home Manager, or the NixOS module |
|
||||||
| [From source](#from-source) | Contributors or custom trees |
|
| [From source](#from-source) | Contributors or custom trees |
|
||||||
| [Manual / PyPI](INSTALL_MANUAL.md) | Full control or pip-only workflows |
|
| [Manual / PyPI](INSTALL_MANUAL.md) | Full control or pip-only workflows |
|
||||||
| [Troubleshooting](TROUBLESHOOTING.md) | Tray, audio, injection, models |
|
| [Troubleshooting](TROUBLESHOOTING.md) | Tray, audio, injection, models |
|
||||||
@@ -185,6 +186,17 @@ sudo snap connect vocalinux:uinput
|
|||||||
|
|
||||||
`--dangerous` is required because this file is not a Store revision. It will not refresh from the Store. After Canonical grants `uinput`, switch to `sudo snap install vocalinux --edge` (or `snap refresh`).
|
`--dangerous` is required because this file is not a Store revision. It will not refresh from the Store. After Canonical grants `uinput`, switch to `sudo snap install vocalinux --edge` (or `snap refresh`).
|
||||||
|
|
||||||
|
## Nix / NixOS
|
||||||
|
|
||||||
|
The repo is a flake: GTK, PyGObject and the AppIndicator typelib come from nixpkgs, and `pywhispercpp` (absent from nixpkgs, same gap as Debian and Fedora) is built from its vendored PyPI sdist. The wrapped binary carries every injector and clipboard tool on PATH.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run github:VocaHQ/vocalinux # try it
|
||||||
|
nix profile install github:VocaHQ/vocalinux
|
||||||
|
```
|
||||||
|
|
||||||
|
On NixOS, `vocalinux.nixosModules.vocalinux` provides `programs.vocalinux.enable`, which installs the package and enables `hardware.uinput`. Add each dictating user to `input` and `uinput` for Wayland shortcuts and ydotool typing. Home Manager users get `vocalinux.homeManagerModules.vocalinux` with the same `programs.vocalinux` options — device permissions stay on the system side. Usage snippets and scope notes: [packaging/nix/README.md](../packaging/nix/README.md).
|
||||||
|
|
||||||
## From source
|
## From source
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
Generated
+27
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1791456040,
|
||||||
|
"narHash": "sha256-H83yz/do+hjOO0uujHyH8RgtIQP2v7Mw+cLwcZK/xKc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e7439b6b14ad3cc35d05608ebca9bce01a25f5f8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
description = "Vocalinux — free, offline voice dictation for Linux";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self, nixpkgs }:
|
||||||
|
let
|
||||||
|
systems = [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
];
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs systems;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = forAllSystems (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
vocalinux = pkgs.python3Packages.callPackage ./packaging/nix/package.nix {
|
||||||
|
pywhispercpp = pkgs.python3Packages.callPackage ./packaging/nix/pywhispercpp.nix { };
|
||||||
|
src = self;
|
||||||
|
};
|
||||||
|
default = self.packages.${system}.vocalinux;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
apps = forAllSystems (system: {
|
||||||
|
vocalinux = {
|
||||||
|
type = "app";
|
||||||
|
program = "${self.packages.${system}.vocalinux}/bin/vocalinux";
|
||||||
|
};
|
||||||
|
default = self.apps.${system}.vocalinux;
|
||||||
|
});
|
||||||
|
|
||||||
|
overlays.default = final: prev: {
|
||||||
|
vocalinux = self.packages.${prev.system}.vocalinux;
|
||||||
|
};
|
||||||
|
|
||||||
|
nixosModules.vocalinux =
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [ ./packaging/nix/module.nix ];
|
||||||
|
programs.vocalinux.package = lib.mkDefault self.packages.${pkgs.system}.vocalinux;
|
||||||
|
};
|
||||||
|
nixosModules.default = self.nixosModules.vocalinux;
|
||||||
|
|
||||||
|
homeManagerModules.vocalinux =
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [ ./packaging/nix/home-manager.nix ];
|
||||||
|
programs.vocalinux.package = lib.mkDefault self.packages.${pkgs.system}.vocalinux;
|
||||||
|
};
|
||||||
|
homeManagerModules.default = self.homeManagerModules.vocalinux;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# Vocalinux for Nix
|
||||||
|
|
||||||
|
A flake that builds Vocalinux against nixpkgs: GTK 3, PyGObject and the
|
||||||
|
AppIndicator typelib come from nixpkgs, and `pywhispercpp` — which nixpkgs
|
||||||
|
does not package — is built from its PyPI sdist (it vendors whisper.cpp and
|
||||||
|
pybind11). Every host tool the app probes for (`xdotool`, `wtype`, `ydotool`,
|
||||||
|
`wl-clipboard`, `xclip`, `xsel`, `xprop`, `setxkbmap`, `ibus`, `gdbus`,
|
||||||
|
`notify-send`, `paplay`, `aplay`) is wired onto PATH, so the wrapped binary
|
||||||
|
behaves like a deb/rpm install with Recommends present.
|
||||||
|
|
||||||
|
## Try it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix run github:VocaHQ/vocalinux
|
||||||
|
```
|
||||||
|
|
||||||
|
or install into a profile:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix profile install github:VocaHQ/vocalinux
|
||||||
|
```
|
||||||
|
|
||||||
|
## NixOS
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs.vocalinux.url = "github:VocaHQ/vocalinux";
|
||||||
|
|
||||||
|
outputs = { nixpkgs, vocalinux, ... }: {
|
||||||
|
nixosConfigurations.host = nixpkgs.lib.nixosSystem {
|
||||||
|
modules = [
|
||||||
|
vocalinux.nixosModules.vocalinux
|
||||||
|
{
|
||||||
|
programs.vocalinux.enable = true;
|
||||||
|
users.users.you.extraGroups = [ "input" "uinput" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`hardware.uinput` (enabled by the module) covers `/dev/uinput`, which ydotool
|
||||||
|
and the evdev backend's keyboard clone need. `input` group membership is a
|
||||||
|
per-user decision — it grants read access to every keyboard and pointer
|
||||||
|
device, the same trade-off `install.sh` documents. X11 sessions need neither
|
||||||
|
and can skip the group lines entirely.
|
||||||
|
|
||||||
|
## Home Manager
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
inputs.home-manager.url = "github:nix-community/home-manager";
|
||||||
|
inputs.home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.vocalinux.url = "github:VocaHQ/vocalinux";
|
||||||
|
|
||||||
|
outputs = { nixpkgs, home-manager, vocalinux, ... }: {
|
||||||
|
homeConfigurations.you = home-manager.lib.homeManagerConfiguration {
|
||||||
|
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||||
|
modules = [
|
||||||
|
vocalinux.homeManagerModules.vocalinux
|
||||||
|
{ programs.vocalinux.enable = true; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Home Manager on NixOS still needs the system-side pieces above (the NixOS
|
||||||
|
module handles `hardware.uinput`; group membership stays per-user). On a
|
||||||
|
non-NixOS host, `nix profile install` plus the equivalent udev rule and group
|
||||||
|
membership from your distro does the same job — see docs/INSTALL.md.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Default engine whisper.cpp plus the `[vad]` extra (ONNX Runtime) are built
|
||||||
|
in. The `vosk`, `whisper`, `parakeet` and `faster_whisper` extras are not
|
||||||
|
packaged (PyTorch footprint / not in nixpkgs).
|
||||||
|
- `pywhispercpp` is built with `GGML_NATIVE=OFF` — a portable baseline rather
|
||||||
|
than `-march=native`, so binaries can move between machines.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Home Manager module for Vocalinux.
|
||||||
|
#
|
||||||
|
# Installs the package into the user profile; device permissions are a
|
||||||
|
# system concern, so pair it with the NixOS module (or the manual group
|
||||||
|
# steps in docs/INSTALL.md) for Wayland/evdev shortcuts and ydotool typing.
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.programs.vocalinux;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.programs.vocalinux = {
|
||||||
|
enable = lib.mkEnableOption "Vocalinux voice dictation";
|
||||||
|
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
defaultText = "the package built by the vocalinux flake";
|
||||||
|
description = "The vocalinux package to install.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
home.packages = [ cfg.package ];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# NixOS module for Vocalinux.
|
||||||
|
#
|
||||||
|
# The flake wraps this file and injects the flake-built package as the
|
||||||
|
# default (programs.vocalinux.package), so importing the module through
|
||||||
|
# nixosModules.vocalinux needs no extra wiring. Imported on its own, set
|
||||||
|
# programs.vocalinux.package to a vocalinux derivation.
|
||||||
|
#
|
||||||
|
# What it cannot do for you: membership in the "input" group is per-user,
|
||||||
|
# so the module documents it and each user opts in:
|
||||||
|
#
|
||||||
|
# users.users.<name>.extraGroups = [ "input" "uinput" ];
|
||||||
|
#
|
||||||
|
# "input" grants read access to every keyboard and pointer device — the
|
||||||
|
# evdev global-shortcut backend needs it on Wayland. X11 sessions need none
|
||||||
|
# of this. See docs/INSTALL.md for the same notes the deb/rpm carry.
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.programs.vocalinux;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.programs.vocalinux = {
|
||||||
|
enable = lib.mkEnableOption "Vocalinux voice dictation";
|
||||||
|
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
defaultText = "the package built by the vocalinux flake";
|
||||||
|
description = "The vocalinux package to install.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
|
# /dev/uinput is what ydotool (native Wayland typing) and the evdev
|
||||||
|
# backend's keyboard clone open. The option loads the module, creates
|
||||||
|
# the "uinput" group and installs the matching udev rule.
|
||||||
|
hardware.uinput.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
# Vocalinux for Nix.
|
||||||
|
#
|
||||||
|
# Consumed by the repo flake (packages.<system>.vocalinux) and buildable with
|
||||||
|
# plain callPackage:
|
||||||
|
#
|
||||||
|
# pkgs.python3Packages.callPackage ./packaging/nix/package.nix {
|
||||||
|
# pywhispercpp = pkgs.python3Packages.callPackage ./packaging/nix/pywhispercpp.nix { };
|
||||||
|
# src = ./.;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# Layout mirrors packaging/native/nfpm.yaml: the interpreter, GTK, PyGObject
|
||||||
|
# and the AppIndicator typelib come from nixpkgs, pywhispercpp is built from
|
||||||
|
# its vendored sdist, and every host tool the injectors probe for
|
||||||
|
# (shutil.which) is wired onto PATH so the packaged binary behaves like the
|
||||||
|
# deb/rpm install with Recommends installed.
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
buildPythonApplication,
|
||||||
|
setuptools,
|
||||||
|
gobject-introspection,
|
||||||
|
wrapGAppsHook3,
|
||||||
|
gtk3,
|
||||||
|
libayatana-appindicator,
|
||||||
|
ibus,
|
||||||
|
libnotify,
|
||||||
|
glib,
|
||||||
|
# Python dependencies (resolved from python3Packages scope).
|
||||||
|
pywhispercpp,
|
||||||
|
pynput,
|
||||||
|
evdev,
|
||||||
|
requests,
|
||||||
|
pysocks,
|
||||||
|
numpy,
|
||||||
|
pyaudio,
|
||||||
|
pygobject3,
|
||||||
|
pycairo,
|
||||||
|
psutil,
|
||||||
|
onnxruntime,
|
||||||
|
tqdm,
|
||||||
|
platformdirs,
|
||||||
|
# Host binaries the app probes for with shutil.which at runtime.
|
||||||
|
xdotool,
|
||||||
|
wtype,
|
||||||
|
ydotool,
|
||||||
|
wl-clipboard,
|
||||||
|
xclip,
|
||||||
|
xsel,
|
||||||
|
xprop,
|
||||||
|
setxkbmap,
|
||||||
|
pulseaudio,
|
||||||
|
alsa-utils,
|
||||||
|
src,
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Host tools the injectors, clipboard fallbacks, audio cues and layout
|
||||||
|
# probing shell out to. Prepending them mirrors installing the deb/rpm
|
||||||
|
# Recommends set. gdbus comes from glib.bin; ibus covers ibus/ibus-daemon.
|
||||||
|
runtimeTools = [
|
||||||
|
xdotool
|
||||||
|
wtype
|
||||||
|
ydotool # provides ydotoold too
|
||||||
|
wl-clipboard # wl-copy / wl-paste
|
||||||
|
xclip
|
||||||
|
xsel
|
||||||
|
xprop
|
||||||
|
setxkbmap
|
||||||
|
ibus
|
||||||
|
libnotify # notify-send
|
||||||
|
pulseaudio # paplay
|
||||||
|
alsa-utils # aplay
|
||||||
|
(lib.getBin glib) # gdbus
|
||||||
|
];
|
||||||
|
in
|
||||||
|
buildPythonApplication {
|
||||||
|
pname = "vocalinux";
|
||||||
|
|
||||||
|
# Track src/vocalinux/version.py so release bumps need no edit here.
|
||||||
|
# builtins.match is POSIX ERE (no \s class), so flatten newlines first.
|
||||||
|
version =
|
||||||
|
let
|
||||||
|
match = builtins.match ''.*__version__ = "([^"]+)".*'' (
|
||||||
|
builtins.replaceStrings [ "\n" ] [ " " ] (
|
||||||
|
builtins.readFile (src + "/src/vocalinux/version.py")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
if match == null then "0.0.0" else builtins.head match;
|
||||||
|
|
||||||
|
inherit src;
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
# Registers GI_TYPELIB_PATH for every buildInput shipping typelibs, and
|
||||||
|
# wraps the entry point with the GLib/GTK environment.
|
||||||
|
gobject-introspection
|
||||||
|
wrapGAppsHook3
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
gtk3 # Gtk-3.0
|
||||||
|
libayatana-appindicator # AyatanaAppIndicator3-0.1 (+ AppIndicator3 fallback)
|
||||||
|
ibus # IBus-1.0 typelib for the Wayland injection engine
|
||||||
|
libnotify # Notify-0.7
|
||||||
|
];
|
||||||
|
|
||||||
|
build-system = [ setuptools ];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
pywhispercpp # default whisper.cpp engine; vendored sdist build
|
||||||
|
pynput # X11 hotkey backend
|
||||||
|
evdev # Wayland/evdev hotkey backend + uinput clone
|
||||||
|
requests
|
||||||
|
pysocks
|
||||||
|
numpy
|
||||||
|
pyaudio
|
||||||
|
pygobject3
|
||||||
|
pycairo
|
||||||
|
psutil
|
||||||
|
onnxruntime # [vad] extra: Silero VAD
|
||||||
|
tqdm # model download progress (pywhispercpp also depends on it)
|
||||||
|
platformdirs
|
||||||
|
];
|
||||||
|
|
||||||
|
# Optional engines are intentionally not packaged: [whisper] pulls PyTorch,
|
||||||
|
# and vosk/sherpa-onnx/faster-whisper are not in nixpkgs. The whisper.cpp
|
||||||
|
# engine remains the default; other engines can be layered on with an
|
||||||
|
# overlay later.
|
||||||
|
|
||||||
|
preFixup = ''
|
||||||
|
gappsWrapperArgs+=(
|
||||||
|
--prefix PATH : ${lib.makeBinPath runtimeTools}
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
install -Dm644 vocalinux.desktop \
|
||||||
|
$out/share/applications/vocalinux.desktop
|
||||||
|
install -Dm644 resources/icons/scalable/vocalinux.svg \
|
||||||
|
$out/share/icons/hicolor/scalable/apps/vocalinux.svg
|
||||||
|
'';
|
||||||
|
|
||||||
|
dontCheck = true; # test suite needs a session bus and X display
|
||||||
|
|
||||||
|
pythonImportsCheck = [ "vocalinux" ];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Free, offline voice dictation for Linux";
|
||||||
|
longDescription = ''
|
||||||
|
Hold a shortcut or toggle dictation and text lands in almost any app on
|
||||||
|
X11 or Wayland. Speech recognition runs locally with whisper.cpp after
|
||||||
|
downloading a model on first use.
|
||||||
|
|
||||||
|
Wayland/evdev shortcuts and ydotool injection need device access: on
|
||||||
|
NixOS enable hardware.uinput and add your user to the "input" and
|
||||||
|
"uinput" groups; the programs.vocalinux NixOS module does the first part.
|
||||||
|
'';
|
||||||
|
homepage = "https://github.com/VocaHQ/vocalinux";
|
||||||
|
license = lib.licenses.agpl3Only;
|
||||||
|
mainProgram = "vocalinux";
|
||||||
|
platforms = lib.platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# pywhispercpp is not in nixpkgs (same gap the .deb/.rpm note in
|
||||||
|
# packaging/native/nfpm.yaml calls out for Debian and Fedora), so the flake
|
||||||
|
# builds it here. The PyPI sdist already vendors whisper.cpp and pybind11, so
|
||||||
|
# no extra source fetches are needed; setup.py drives CMake from build_ext.
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
buildPythonPackage,
|
||||||
|
fetchPypi,
|
||||||
|
setuptools,
|
||||||
|
wheel,
|
||||||
|
cmake,
|
||||||
|
numpy,
|
||||||
|
requests,
|
||||||
|
tqdm,
|
||||||
|
platformdirs,
|
||||||
|
autoPatchelfHook,
|
||||||
|
stdenv,
|
||||||
|
}:
|
||||||
|
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "pywhispercpp";
|
||||||
|
version = "1.5.1";
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-XfiX5d2dnxaAT8k3vYW59YgKCymlX4hDWF4OA9dhleU=";
|
||||||
|
};
|
||||||
|
|
||||||
|
# python -m build verifies every build-system.requires entry resolves to an
|
||||||
|
# installed Python package. The ones setup.py never imports are dropped:
|
||||||
|
# ninja is try/except'd (Unix Makefiles are the fallback), repairwheel only
|
||||||
|
# runs on Windows, setuptools-scm is unused, and cmake is a PATH tool, not a
|
||||||
|
# Python package.
|
||||||
|
postPatch = ''
|
||||||
|
substituteInPlace pyproject.toml \
|
||||||
|
--replace-fail ' "ninja",' "" \
|
||||||
|
--replace-fail ' "cmake>=3.12",' "" \
|
||||||
|
--replace-fail ' "repairwheel",' "" \
|
||||||
|
--replace-fail ' "setuptools-scm>=8"' ""
|
||||||
|
|
||||||
|
# setup() passes no version, so without setuptools-scm the wheel metadata
|
||||||
|
# lands as 0.0.0; get_version() reads PYWHISPERCPP_VERSION instead.
|
||||||
|
substituteInPlace setup.py \
|
||||||
|
--replace-fail ' name="pywhispercpp",' ' name="pywhispercpp", version=get_version(),'
|
||||||
|
'';
|
||||||
|
|
||||||
|
env = {
|
||||||
|
# The sdist ships no version.txt; setup.py falls back to this env var.
|
||||||
|
PYWHISPERCPP_VERSION = version;
|
||||||
|
# One static extension module (BUILD_SHARED_LIBS defaults ON upstream and
|
||||||
|
# would need $ORIGIN rpath repair that never runs outside cibuildwheel) and
|
||||||
|
# a portable baseline instead of -march=native.
|
||||||
|
CMAKE_ARGS = "-DBUILD_SHARED_LIBS=OFF -DGGML_NATIVE=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON";
|
||||||
|
};
|
||||||
|
|
||||||
|
# env attrs are exported verbatim; expanding the core count needs a shell
|
||||||
|
# phase.
|
||||||
|
preBuild = ''
|
||||||
|
export CMAKE_BUILD_PARALLEL_LEVEL="$NIX_BUILD_CORES"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# cmake is only here so setup.py's build_ext can invoke it; letting the
|
||||||
|
# cmake configure hook run standalone leaves a build/ dir that breaks the
|
||||||
|
# pypa wheel build.
|
||||||
|
dontUseCmakeConfigure = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
cmake
|
||||||
|
autoPatchelfHook
|
||||||
|
];
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
setuptools
|
||||||
|
wheel
|
||||||
|
];
|
||||||
|
|
||||||
|
# libstdc++/libgomp for the compiled extension.
|
||||||
|
buildInputs = [ stdenv.cc.cc.lib ];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
numpy
|
||||||
|
requests
|
||||||
|
tqdm
|
||||||
|
platformdirs
|
||||||
|
];
|
||||||
|
|
||||||
|
# pywhispercpp.model pulls in the compiled _pywhispercpp extension, so
|
||||||
|
# checking all three proves the native binding loads, not just the package.
|
||||||
|
pythonImportsCheck = [ "pywhispercpp" "pywhispercpp.model" "_pywhispercpp" ];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Python bindings for whisper.cpp";
|
||||||
|
homepage = "https://github.com/absadiki/pywhispercpp";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
platforms = lib.platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user