-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add NixOS module, Nix shell and overlay
- Loading branch information
Showing
7 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
description = "This is the runner for Project-W, a service that converts uploaded audio files into downloadable text transcripts using OpenAIs whisper AI model, hosted on a backend server and dedicated runners."; | ||
|
||
inputs = { | ||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; | ||
systems.url = "github:nix-systems/default"; | ||
}; | ||
|
||
outputs = inputs@{ nixpkgs, systems, ...}: | ||
let | ||
pythonOverlay = import ./nix/overlay.nix; | ||
eachSystem = nixpkgs.lib.genAttrs (import systems); | ||
pkgsFor = eachSystem (system: | ||
import nixpkgs { | ||
inherit system; | ||
#overlays add all new packages and their dependencies | ||
overlays = [pythonOverlay]; | ||
} | ||
); | ||
in { | ||
packages = eachSystem (system: rec { | ||
default = project-W-runner; | ||
project-W-runner = pkgsFor.${system}.python3Packages.project-W-runner; | ||
}); | ||
devShells = eachSystem (system: { | ||
default = import ./nix/shell.nix { pkgs=pkgsFor.${system}; }; | ||
}); | ||
nixosModules.default = import ./nix/module.nix inputs; | ||
overlays.default = pythonOverlay; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
inputs: {config, lib, pkgs, ...}: | ||
let | ||
inherit (pkgs.stdenv.hostPlatform) system; | ||
inherit (lib) | ||
mdDoc | ||
mkIf | ||
mkOption | ||
mkEnableOption | ||
types | ||
getExe | ||
escapeShellArgs | ||
; | ||
cfg = config.services.project-W-runner; | ||
cfg_str = "services.project-W-runner"; | ||
in { | ||
options = { | ||
services.project-W-runner = { | ||
enable = mkEnableOption (mdDoc "Runner of Project-W"); | ||
package = mkOption { | ||
type = types.package; | ||
default = inputs.self.packages.${system}.project-W-runner; | ||
description = mdDoc '' | ||
Project-W runner python package to use. | ||
''; | ||
}; | ||
user = mkOption { | ||
type = types.singleLineStr; | ||
default = "project-W-runner"; | ||
description = mdDoc '' | ||
User account under which the runner runs. | ||
''; | ||
}; | ||
group = mkOption { | ||
type = types.singleLineStr; | ||
default = "project-W-runner"; | ||
description = mdDoc '' | ||
User group under which the runner runs. | ||
''; | ||
}; | ||
settings = { | ||
runnerToken = mkOption { | ||
type = types.singleLineStr; | ||
default = "\${RUNNER_TOKEN}"; | ||
description = mdDoc '' | ||
Token that the runner uses to authenticate with the backend. Warning: This will be public in the /nix/store! For production systems please use [envFile](${cfg_str}.envFile) combined with a secret management tool like sops-nix instead!!! | ||
''; | ||
}; | ||
backendURL = mkOption { | ||
type = types.strMatching "^(http|https):\/\/(([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9\-]+|localhost)(:[0-9]+)?((\/[a-zA-Z0-9\-]+)+)?$$"; | ||
example = "https://example.com"; | ||
description = mdDoc '' | ||
URL under which the backend is hosted (including http/https, port, shouldn't end with /). | ||
''; | ||
}; | ||
modelCacheDir = mkOption { | ||
type = types.singleLineStr; | ||
default = "/var/cache/project-W-runner_whisperCache"; | ||
description = mdDoc '' | ||
Directory used to cache whisper AI models. | ||
''; | ||
}; | ||
torchDevice = mkOption { | ||
type = types.nullOr types.singleLineStr; | ||
default = null; | ||
example = "cuda:1"; | ||
description = mdDoc '' | ||
The PyTorch device used by Whisper. If set to null then pytorches default device will be used. | ||
''; | ||
}; | ||
}; | ||
envOptions = mkOption { | ||
type = types.listOf types.singleLineStr; | ||
default = [ "runnerToken" ]; | ||
description = mdDoc '' | ||
Attributes that require loading of environment variables. An !ENV will be added to the yaml config for these. Just add the name of the attribute itself, not the name of the attribute set(s) it is in. | ||
''; | ||
}; | ||
envFile = mkOption { | ||
type = types.nullOr types.singleLineStr; | ||
default = null; | ||
example = "/run/secrets/secretFile"; | ||
description = mdDoc '' | ||
Path to file to load secrets from. All secrets should be written as environment variables (in NAME=VALUE declerations, one per line). Per default, RUNNER_TOKEN sets the runner token. The content of the file most likely should look like this: | ||
``` | ||
RUNNER_TOKEN=<your runners token> | ||
``` | ||
This file should be accessable by the user [user](${cfg_str}.user) and by this user only! | ||
''; | ||
}; | ||
}; | ||
}; | ||
|
||
config = | ||
let | ||
stringsToReplace = builtins.map (x: x + ":") cfg.envOptions; | ||
newStrings = builtins.map (x: x + " !ENV") stringsToReplace; | ||
filteredSettings = pkgs.lib.filterAttrsRecursive (name: value: value != null) cfg.settings; | ||
fileWithoutEnvs = (pkgs.formats.yaml { }).generate "project-W-runner-config-without-env.yaml" filteredSettings; | ||
configFile = pkgs.writeTextDir "config.yml" (builtins.replaceStrings stringsToReplace newStrings (builtins.readFile fileWithoutEnvs)); | ||
#function that checks if we have attributes in cfg.envOptions that are not strings | ||
invalidEnvOption = (attrSet: | ||
let | ||
v = builtins.attrValues attrSet; | ||
boolFunc = (element: | ||
if (builtins.isAttrs element) then (invalidEnvOption element) | ||
else if (builtins.elem element cfg.envOptions && !(builtins.isString element)) then true | ||
else false | ||
); | ||
iterateV = (i: | ||
if (i >= (builtins.length v)) then false | ||
else if (boolFunc (builtins.elemAt v i)) then true | ||
else iterateV (i+1) | ||
); | ||
in | ||
iterateV 0 | ||
); | ||
in mkIf cfg.enable { | ||
assertions = [ | ||
{ | ||
assertion = !(invalidEnvOption cfg.settings); | ||
message = "The ${cfg_str}.envOptions option cannot contain attributes that are not some kind of string in ${cfg_str}.settings"; | ||
} | ||
{ | ||
assertion = cfg.envOptions == [] || cfg.envFile != null; | ||
message = "The ${cfg_str}.envFile option can't be null if ${cfg_str}.envOptions contains elements. Per default the runner token ${cfg_str}.settings.runnerToken has to be set in envFile."; | ||
} | ||
]; | ||
|
||
systemd = { | ||
#create directories for persistent stuff | ||
tmpfiles.settings.project-W-runner-dirs = { | ||
"${cfg.settings.modelCacheDir}"."d" = { | ||
mode = "700"; | ||
inherit (cfg) user group; | ||
}; | ||
}; | ||
|
||
#setup systemd service for runner | ||
services.project-W-runner = { | ||
description = "Project-W runner"; | ||
after = [ "network-online.target" ]; | ||
wants = [ "network-online.target" ]; | ||
wantedBy = [ "multi-user.target" ]; | ||
serviceConfig = { | ||
Type = "simple"; | ||
User = cfg.user; | ||
Group = cfg.group; | ||
UMask = "0077"; | ||
ExecStart = escapeShellArgs [ | ||
"${getExe cfg.package}" | ||
"--customConfigPath" "${configFile}" | ||
]; | ||
PrivateTmp = true; | ||
EnvironmentFile = mkIf (cfg.envFile != null) cfg.envFile; | ||
}; | ||
}; | ||
}; | ||
|
||
#setup user/group under which systemd service is run | ||
users.users = mkIf (cfg.user == "project-W-runner") { | ||
project-W-runner = { | ||
inherit (cfg) group; | ||
isSystemUser = true; | ||
}; | ||
}; | ||
users.groups = mkIf (cfg.group == "project-W-runner") { | ||
project-W-runner = {}; | ||
}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
(final: prev: { | ||
python3 = prev.python3.override { | ||
packageOverrides = pyfinal: pyprev: { | ||
pyaml-env = prev.callPackage ./pkgs/pyaml-env.nix { }; | ||
project-W-runner = prev.callPackage ./pkgs/project-W-runner.nix { }; | ||
}; | ||
}; | ||
python3Packages = final.python3.pkgs; | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
{ | ||
lib, | ||
ffmpeg, | ||
python3Packages | ||
}: | ||
|
||
python3Packages.buildPythonPackage rec { | ||
pname = "project_W_runner"; | ||
version = "0.0.1"; | ||
format = "setuptools"; | ||
|
||
src = ../../.; | ||
|
||
nativeBuildInputs = with python3Packages; [ | ||
setuptools-scm | ||
]; | ||
buildInputs = [ | ||
ffmpeg | ||
]; | ||
propagatedBuildInputs = with python3Packages; [ | ||
aiohttp | ||
click | ||
jsonschema | ||
openai-whisper | ||
numpy | ||
platformdirs | ||
pyaml-env | ||
]; | ||
|
||
nativeCheckInputs = with python3Packages; [ | ||
pytestCheckHook | ||
pytest-cov | ||
]; | ||
pythonImportsCheck = [ pname ]; | ||
|
||
#hardcode version so that setuptools-scm works without .git folder: | ||
SETUPTOOLS_SCM_PRETEND_VERSION = version; | ||
|
||
meta = { | ||
description = "Runner for Project-W"; | ||
homepage = "https://github.com/JulianFP/project-W-runner"; | ||
license = lib.licenses.mit; | ||
mainProgram = pname; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
lib, | ||
fetchPypi, | ||
python3Packages | ||
}: | ||
|
||
python3Packages.buildPythonPackage rec { | ||
pname = "pyaml-env"; | ||
version = "1.2.1"; | ||
src = fetchPypi { | ||
inherit version; | ||
pname = "pyaml_env"; | ||
sha256 = "sha256-bV3JjIyC33Q6EywZbnmWMFDJ/rBbCm8l8613dx09lbA="; | ||
}; | ||
doCheck = false; | ||
propagatedBuildInputs = with python3Packages; [ | ||
pyyaml | ||
]; | ||
meta = { | ||
description = "Parse YAML configuration with environment variables in Python"; | ||
homepage = "https://github.com/mkaranasou/pyaml_env"; | ||
license = lib.licenses.mit; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
let | ||
dontCheckPythonPkg = drv: drv.overridePythonAttrs (old: { doCheck = false; }); | ||
myPythonPackages = ps: with ps; [ | ||
#all required dependencies + this projects package itself (required for sphinx) | ||
(dontCheckPythonPkg project-W-runner) | ||
|
||
#optional dependencies: tests | ||
pytest | ||
pytest-cov | ||
]; | ||
in | ||
{ pkgs ? import <nixpkgs> { } }: | ||
pkgs.mkShell { | ||
buildInputs = with pkgs; [ | ||
(python3.withPackages myPythonPackages) | ||
]; | ||
} |