mirror of
https://github.com/Smaug123/PulumiConfig
synced 2025-10-05 08:38:41 +00:00
Whisper (#26)
This commit is contained in:
1
PulumiWebServer/.gitignore
vendored
Normal file
1
PulumiWebServer/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
venv/
|
@@ -102,6 +102,7 @@ type WellKnownSubdomain =
|
|||||||
| WoodpeckerAgent
|
| WoodpeckerAgent
|
||||||
| Grafana
|
| Grafana
|
||||||
| PureGym
|
| PureGym
|
||||||
|
| Whisper
|
||||||
|
|
||||||
override this.ToString () =
|
override this.ToString () =
|
||||||
match this with
|
match this with
|
||||||
@@ -113,6 +114,7 @@ type WellKnownSubdomain =
|
|||||||
| Woodpecker -> "woodpecker"
|
| Woodpecker -> "woodpecker"
|
||||||
| WoodpeckerAgent -> "woodpecker-agent"
|
| WoodpeckerAgent -> "woodpecker-agent"
|
||||||
| PureGym -> "puregym"
|
| PureGym -> "puregym"
|
||||||
|
| Whisper -> "whisper"
|
||||||
|
|
||||||
static member Parse (s : string) =
|
static member Parse (s : string) =
|
||||||
match s with
|
match s with
|
||||||
@@ -124,6 +126,7 @@ type WellKnownSubdomain =
|
|||||||
| "woodpecker-agent" -> WellKnownSubdomain.WoodpeckerAgent
|
| "woodpecker-agent" -> WellKnownSubdomain.WoodpeckerAgent
|
||||||
| "grafana" -> WellKnownSubdomain.Grafana
|
| "grafana" -> WellKnownSubdomain.Grafana
|
||||||
| "puregym" -> WellKnownSubdomain.PureGym
|
| "puregym" -> WellKnownSubdomain.PureGym
|
||||||
|
| "whisper" -> WellKnownSubdomain.Whisper
|
||||||
| _ -> failwith $"Failed to deserialise: {s}"
|
| _ -> failwith $"Failed to deserialise: {s}"
|
||||||
|
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
nixpkgs,
|
nixpkgs,
|
||||||
website,
|
website,
|
||||||
puregym-client,
|
puregym-client,
|
||||||
|
whisper-packages,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
lib = nixpkgs.lib;
|
lib = nixpkgs.lib;
|
||||||
@@ -24,6 +25,7 @@ in {
|
|||||||
# generated at runtime by nixos-infect and copied here
|
# generated at runtime by nixos-infect and copied here
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
./networking.nix
|
./networking.nix
|
||||||
|
./whisper/whisper.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
services.radicale-config.domain = userConfig.domain;
|
services.radicale-config.domain = userConfig.domain;
|
||||||
@@ -47,6 +49,8 @@ in {
|
|||||||
services.prometheus-config.domain-exporter-domains = [userConfig.domain];
|
services.prometheus-config.domain-exporter-domains = [userConfig.domain];
|
||||||
services.puregym-config.domain = userConfig.domain;
|
services.puregym-config.domain = userConfig.domain;
|
||||||
services.puregym-config.subdomain = "puregym";
|
services.puregym-config.subdomain = "puregym";
|
||||||
|
services.whisper-config.domain = userConfig.domain;
|
||||||
|
services.whisper-config.subdomain = "whisper";
|
||||||
|
|
||||||
services.journald.extraConfig = "SystemMaxUse=100M";
|
services.journald.extraConfig = "SystemMaxUse=100M";
|
||||||
|
|
||||||
|
222
PulumiWebServer/Nix/flake.lock
generated
222
PulumiWebServer/Nix/flake.lock
generated
@@ -99,6 +99,24 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_3"
|
"systems": "systems_3"
|
||||||
},
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701680307,
|
||||||
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_4": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_4"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694529238,
|
"lastModified": 1694529238,
|
||||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
@@ -113,6 +131,24 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-utils_5": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_5"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1701680307,
|
||||||
|
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -120,11 +156,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703795120,
|
"lastModified": 1705660020,
|
||||||
"narHash": "sha256-Scr4fwfGn03zwFgM7IltT8hqbFDkHvymnF5AaR4eDAg=",
|
"narHash": "sha256-1tOuNh+UbiZlaC8RrpQzzypgnLBC67eRlBunfkE4sbQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "ba6b75011b44e85b1b755b6c423f85d0817645f7",
|
"rev": "2064348e555b6aa963da6372a8f14e6acb80a176",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -139,17 +175,15 @@
|
|||||||
"website",
|
"website",
|
||||||
"flake-utils"
|
"flake-utils"
|
||||||
],
|
],
|
||||||
"nixpkgs": [
|
"nixpkgs": "nixpkgs_5",
|
||||||
"website",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"scripts": "scripts_2"
|
"scripts": "scripts_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dirtyRev": "9e2f5603f1e4e263e73ae0d0ca7c86ae14427c73-dirty",
|
"lastModified": 1704152342,
|
||||||
"dirtyShortRev": "9e2f560-dirty",
|
"narHash": "sha256-9ntmhbkkmZSoaVMYPmZ/HkzYphpIHIBrWv5viO2Ee48=",
|
||||||
"lastModified": 1701513782,
|
"ref": "refs/heads/main",
|
||||||
"narHash": "sha256-dDym75Eq6TIw9IrokBWwSoto0/l3nxFGpH4/VZkeqrQ=",
|
"rev": "882c5d5703e639a1318ea4e69f3b8cbbfacfb3a0",
|
||||||
|
"revCount": 19,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "file:/Users/patrick/Desktop/website/static-site-images"
|
"url": "file:/Users/patrick/Desktop/website/static-site-images"
|
||||||
},
|
},
|
||||||
@@ -160,21 +194,15 @@
|
|||||||
},
|
},
|
||||||
"katex": {
|
"katex": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": [
|
"flake-utils": "flake-utils_4",
|
||||||
"website",
|
"nixpkgs": "nixpkgs_6"
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"website",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1696151934,
|
"lastModified": 1704150937,
|
||||||
"narHash": "sha256-8kihcqdgYjoVuGozfgfcWh81yqMUvns4+C/fgkn+RNQ=",
|
"narHash": "sha256-G6uJKkY5VErgobe51IIbp/ugHDIhVx5e0xNjJ90JEOk=",
|
||||||
"owner": "Smaug123",
|
"owner": "Smaug123",
|
||||||
"repo": "KaTeX",
|
"repo": "KaTeX",
|
||||||
"rev": "ac1f9b30441f63ea20216a36ffa7148dc0e9a9b3",
|
"rev": "b74ed701beec2bebd161a0b5ea30c496c5206b96",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -184,13 +212,25 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"model": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"narHash": "sha256-CSrDFPoQgkvBW36keGkYpjxz740TBrCKVSxwSnfYvV8=",
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin?download=true"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin?download=true"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703467016,
|
"lastModified": 1705458851,
|
||||||
"narHash": "sha256-/5A/dNPhbQx/Oa2d+Get174eNI3LERQ7u6WTWOlR1eQ=",
|
"narHash": "sha256-uQvEhiv33Zj/Pv364dTvnpPwFSptRZgVedDzoM+HqVg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d02d818f22c777aa4e854efc3242ec451e5d462a",
|
"rev": "8bf65f17d8070a0a490daf5f1c784b87ee73982c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -202,11 +242,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703351344,
|
"lastModified": 1705033721,
|
||||||
"narHash": "sha256-9FEelzftkE9UaJ5nqxidaJJPEhe9TPhbypLHmc2Mysc=",
|
"narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "7790e078f8979a9fcd543f9a47427eeaba38f268",
|
"rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -233,11 +273,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703134684,
|
"lastModified": 1704842529,
|
||||||
"narHash": "sha256-SQmng1EnBFLzS7WSRyPM9HgmZP2kLJcPAz+Ug/nug6o=",
|
"narHash": "sha256-OTeQA+F8d/Evad33JMfuXC89VMetQbsU4qcaePchGr4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d6863cbcbbb80e71cecfc03356db1cda38919523",
|
"rev": "eabe8d3eface69f5bb16c18f8662a702f50c20d5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -262,6 +302,52 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704150997,
|
||||||
|
"narHash": "sha256-HbBTRybyqmd2/OMHIA6bV8HNXpcwB/t49be2kBq13IE=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2df2bddf079263a6da2eb1876c7e212188ff950c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_6": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1688392541,
|
||||||
|
"narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-22.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_7": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1695033101,
|
||||||
|
"narHash": "sha256-RQ4m+ycjdLdass7Hr4+Lzwnjw7wGhcUkKqWiJS3YxPM=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d941d9491804e0ca01e03468dbf6f8d3a7919a16",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"pdfs": {
|
"pdfs": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": [
|
"flake-utils": [
|
||||||
@@ -294,11 +380,11 @@
|
|||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703797686,
|
"lastModified": 1703937582,
|
||||||
"narHash": "sha256-4HZ+uz7LFK+44IzKuLe9lL34Oau/J1Tppmxpe+x5FCw=",
|
"narHash": "sha256-M4y/xbrocPoLwG4qUUdCoBvOHumPAGlMoeo8SpWjn0M=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "8ece87ff57b0ae66f38120d8a26b33661625fa61",
|
"rev": "cdbc73b07f3cac88e446fbe73c4b0c6616448319",
|
||||||
"revCount": 5,
|
"revCount": 8,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitea.patrickstevens.co.uk/patrick/puregym-unofficial-dotnet"
|
"url": "https://gitea.patrickstevens.co.uk/patrick/puregym-unofficial-dotnet"
|
||||||
},
|
},
|
||||||
@@ -313,7 +399,8 @@
|
|||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"puregym-client": "puregym-client",
|
"puregym-client": "puregym-client",
|
||||||
"sops": "sops",
|
"sops": "sops",
|
||||||
"website": "website"
|
"website": "website",
|
||||||
|
"whisper-packages": "whisper-packages"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -382,11 +469,11 @@
|
|||||||
"nixpkgs-stable": "nixpkgs-stable"
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703387502,
|
"lastModified": 1705356877,
|
||||||
"narHash": "sha256-JnWuQmyanPtF8c5yAEFXVWzaIlMxA3EAZCh8XNvnVqE=",
|
"narHash": "sha256-274jL1cH64DcXUXebVMZBRUsTs3FvFlPIPkCN/yhSnI=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "e523e89763ff45f0a6cf15bcb1092636b1da9ed3",
|
"rev": "87755331580fdf23df7e39b46d63ac88236bf42c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -440,6 +527,36 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_4": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"website": {
|
"website": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"anki-decks": "anki-decks",
|
"anki-decks": "anki-decks",
|
||||||
@@ -454,11 +571,11 @@
|
|||||||
"scripts": "scripts_4"
|
"scripts": "scripts_4"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701514896,
|
"lastModified": 1705693021,
|
||||||
"narHash": "sha256-XDhco86dHsoHzezarG1UQBpsCyZ+AqRY+w+l3g4hL1o=",
|
"narHash": "sha256-Ew7yxjYvwG9IE6YNPxcHNQUn2T8es1yWoK/f+x7UyCM=",
|
||||||
"owner": "Smaug123",
|
"owner": "Smaug123",
|
||||||
"repo": "static-site-pipeline",
|
"repo": "static-site-pipeline",
|
||||||
"rev": "b35c219d0e3e93b5bbd52befa486b54fa4e8b710",
|
"rev": "da3a4d2e53e3068755fcd49b74bcfcf2800c197d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -466,6 +583,27 @@
|
|||||||
"repo": "static-site-pipeline",
|
"repo": "static-site-pipeline",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"whisper-packages": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_5",
|
||||||
|
"model": "model",
|
||||||
|
"nixpkgs": "nixpkgs_7"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1704121990,
|
||||||
|
"narHash": "sha256-ss1gDu3C7anyqEo0ksDuOPgcsD3EOUqtCwAt8ei6rM4=",
|
||||||
|
"owner": "Smaug123",
|
||||||
|
"repo": "whisper.cpp",
|
||||||
|
"rev": "2ff0257983b4a3fe9cece30b215ba2b5087f2613",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Smaug123",
|
||||||
|
"ref": "nix-small",
|
||||||
|
"repo": "whisper.cpp",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
sops.url = "github:Mic92/sops-nix";
|
sops.url = "github:Mic92/sops-nix";
|
||||||
|
whisper-packages.url = "github:Smaug123/whisper.cpp/nix-small";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
home-manager,
|
home-manager,
|
||||||
website,
|
website,
|
||||||
puregym-client,
|
puregym-client,
|
||||||
|
whisper-packages,
|
||||||
} @ inputs: let
|
} @ inputs: let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
in {
|
in {
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
inherit system;
|
inherit system;
|
||||||
website = website.packages.${system}.default;
|
website = website.packages.${system}.default;
|
||||||
puregym-client = puregym-client.packages.${system}.default;
|
puregym-client = puregym-client.packages.${system}.default;
|
||||||
|
whisper-packages = whisper-packages.packages.${system};
|
||||||
};
|
};
|
||||||
modules = [
|
modules = [
|
||||||
(import ./configuration.nix (inputs // {inherit inputs;}))
|
(import ./configuration.nix (inputs // {inherit inputs;}))
|
||||||
|
2
PulumiWebServer/Nix/whisper/requirements.txt
Normal file
2
PulumiWebServer/Nix/whisper/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
flask
|
||||||
|
waitress
|
107
PulumiWebServer/Nix/whisper/transcribe.html
Normal file
107
PulumiWebServer/Nix/whisper/transcribe.html
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Whisper Transcription</title>
|
||||||
|
<style>
|
||||||
|
#output {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
width: 95%;
|
||||||
|
height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Whisper Transcription</h1>
|
||||||
|
<p>Submit file for transcription</p>
|
||||||
|
<form action="/upload" method="POST" enctype="multipart/form-data">
|
||||||
|
<input type="file" name="file">
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="file-to-analyze">File to analyze:</label>
|
||||||
|
<div contenteditable="true" id="file-to-analyze">{no file set}</div>
|
||||||
|
</div>
|
||||||
|
<button id="start">Start analysing</button>
|
||||||
|
|
||||||
|
<button id="displayWav" hidden="hidden">Listen to file being transcribed</button>
|
||||||
|
<div id="wavContainer"></div>
|
||||||
|
|
||||||
|
<div id="status"></div>
|
||||||
|
<div id="output"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const uploadForm = document.querySelector('form');
|
||||||
|
const uploadResultDiv = document.getElementById('file-to-analyze');
|
||||||
|
uploadForm.addEventListener('submit', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const files = document.querySelector('[type=file]').files;
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', files[0]);
|
||||||
|
|
||||||
|
fetch('/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(response => {
|
||||||
|
uploadResultDiv.innerText = response;
|
||||||
|
})
|
||||||
|
.catch(error => console.error(error))
|
||||||
|
});
|
||||||
|
|
||||||
|
const outputDiv = document.getElementById('output');
|
||||||
|
const statusDiv = document.getElementById('status');
|
||||||
|
const displayButton = document.getElementById('displayWav');
|
||||||
|
const wavContainer = document.getElementById('wavContainer');
|
||||||
|
const startButton = document.getElementById('start');
|
||||||
|
|
||||||
|
startButton.onclick = function() {
|
||||||
|
// Create a new EventSource instance pointing to the SSE route
|
||||||
|
// const eventSource = new EventSource('/transcribe-youtube?url=https://www.youtube.com/watch?v=-xZQ0YZ7ls4');
|
||||||
|
const eventSource = new EventSource('/transcribe-file?file=' + uploadResultDiv.innerText);
|
||||||
|
|
||||||
|
let file = '';
|
||||||
|
|
||||||
|
displayButton.onclick = function () {
|
||||||
|
const audioElt = document.createElement('audio');
|
||||||
|
audioElt.controls = true;
|
||||||
|
audioElt.src = '/download?file=' + file;
|
||||||
|
|
||||||
|
wavContainer.innerHTML = '';
|
||||||
|
wavContainer.appendChild(audioElt);
|
||||||
|
};
|
||||||
|
|
||||||
|
eventSource.addEventListener('started', function (e) {
|
||||||
|
statusDiv.innerText = 'Transcription has begun. Please hold the line; my server is only very small and weedy.';
|
||||||
|
displayButton.hidden = false;
|
||||||
|
file = e.data;
|
||||||
|
});
|
||||||
|
|
||||||
|
eventSource.addEventListener('quit', function (e) {
|
||||||
|
statusDiv.innerText = 'Transcription finished';
|
||||||
|
eventSource.close()
|
||||||
|
});
|
||||||
|
|
||||||
|
eventSource.onmessage = function (e) {
|
||||||
|
outputDiv.innerText += e.data + '\n';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle any errors
|
||||||
|
eventSource.onerror = function (e) {
|
||||||
|
if (eventSource.readyState === EventSource.CLOSED) {
|
||||||
|
console.log('Connection was closed');
|
||||||
|
} else {
|
||||||
|
outputDiv.innerText += 'Error! Connection was lost. Refresh the page to retry.\n';
|
||||||
|
eventSource.close()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
65
PulumiWebServer/Nix/whisper/whisper.nix
Normal file
65
PulumiWebServer/Nix/whisper/whisper.nix
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
whisper-packages,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options = {
|
||||||
|
services.whisper-config = {
|
||||||
|
domain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "example.com";
|
||||||
|
description = lib.mdDoc "Top-level domain to configure";
|
||||||
|
};
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "whisper";
|
||||||
|
description = lib.mdDoc "Subdomain in which to put the Whisper server";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
description = lib.mdDoc "Whisper localhost port to be forwarded";
|
||||||
|
default = 1739;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
users.users."whisper".extraGroups = [config.users.groups.keys.name];
|
||||||
|
users.users."whisper".group = "whisper";
|
||||||
|
users.groups.whisper = {};
|
||||||
|
users.users."whisper".isSystemUser = true;
|
||||||
|
|
||||||
|
systemd.services.whisper-server = {
|
||||||
|
description = "whisper-server";
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
serviceConfig = let
|
||||||
|
python = pkgs.python3.withPackages (p: with p; [flask waitress]);
|
||||||
|
in {
|
||||||
|
Restart = "always";
|
||||||
|
Type = "exec";
|
||||||
|
User = "whisper";
|
||||||
|
Group = "whisper";
|
||||||
|
ExecStart = "${python}/bin/python ${./whisper.py}";
|
||||||
|
};
|
||||||
|
environment = {
|
||||||
|
WHISPER_NORMALIZE = "${whisper-packages.normalize}/bin/normalize.sh";
|
||||||
|
WHISPER_CLIENT = "${whisper-packages.default}/bin/whisper-cpp";
|
||||||
|
WHISPER_PORT = toString config.services.whisper-config.port;
|
||||||
|
INDEX_PAGE_PATH = ./transcribe.html;
|
||||||
|
YT_DLP = "${pkgs.yt-dlp}/bin/yt-dlp";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.proxyTimeout = "300s";
|
||||||
|
services.nginx.clientMaxBodySize = "50M";
|
||||||
|
services.nginx.virtualHosts."${config.services.whisper-config.subdomain}.${config.services.whisper-config.domain}" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://localhost:${toString config.services.whisper-config.port}/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
129
PulumiWebServer/Nix/whisper/whisper.py
Normal file
129
PulumiWebServer/Nix/whisper/whisper.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
from typing import AnyStr
|
||||||
|
import re
|
||||||
|
from flask import Flask, Response, request, render_template_string
|
||||||
|
import waitress
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
youtube_regex = re.compile(
|
||||||
|
r"^(?:https?://)?(?:www\.)?(?:youtu\.be/|youtube\.com/(?:embed/|v/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$")
|
||||||
|
|
||||||
|
alnum_regex = re.compile(r"^[a-zA-Z0-9]+$")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_output(wav_file):
|
||||||
|
process = subprocess.Popen([whisper, "--file", f"/tmp/whisper/{wav_file}.wav", "--output-txt"],
|
||||||
|
stdout=subprocess.PIPE, bufsize=1,
|
||||||
|
text=True)
|
||||||
|
|
||||||
|
yield f'event: started\ndata: {wav_file}\n\n'
|
||||||
|
|
||||||
|
for line in iter(process.stdout.readline, ''):
|
||||||
|
yield f"data: {line}\n\n"
|
||||||
|
|
||||||
|
yield 'event: quit\ndata: \n\n'
|
||||||
|
|
||||||
|
os.remove(f"/tmp/whisper/{wav_file}.wav")
|
||||||
|
|
||||||
|
|
||||||
|
def obtain_youtube(url: AnyStr) -> str:
|
||||||
|
# handle, temp_file = tempfile.mkstemp(".wav", text=False)
|
||||||
|
# os.close(handle)
|
||||||
|
# os.remove(temp_file)
|
||||||
|
|
||||||
|
# output = subprocess.run(
|
||||||
|
# [ytdlp, '--extract-audio', '--audio-format', 'wav', '--cookies', '/tmp/cookies.txt', '--audio-quality', '16k', '--force-ipv6', '--output', temp_file,
|
||||||
|
# url], check=True, capture_output=True, text=True)
|
||||||
|
# if "429 Too Many Requests" in output.stdout:
|
||||||
|
# raise subprocess.CalledProcessError(1, whisper, "YouTube replied saying Too Many Requests")
|
||||||
|
# return temp_file
|
||||||
|
|
||||||
|
raise Exception("DigitalOcean is rate limited to YouTube")
|
||||||
|
|
||||||
|
|
||||||
|
def normalize(path: str, output: str):
|
||||||
|
try:
|
||||||
|
subprocess.run([normalize_binary, path, output], check=True)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
os.remove(path)
|
||||||
|
return Response("failed to normalize", status=500)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/transcribe-youtube')
|
||||||
|
def transcribe_youtube():
|
||||||
|
try:
|
||||||
|
url = request.args.get('url')
|
||||||
|
except KeyError:
|
||||||
|
return Response("must have a URL in the format ?url=https://www.youtube.com/watch?v=...", status=400)
|
||||||
|
if youtube_regex.match(url) is None:
|
||||||
|
return Response(f"url '{url}' did not appear to be a YouTube video", status=400)
|
||||||
|
wav_file = obtain_youtube(url)
|
||||||
|
return Response(generate_output(wav_file), mimetype="text/event-stream")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/transcribe-file')
|
||||||
|
def transcribe_file():
|
||||||
|
try:
|
||||||
|
file = request.args.get('file')
|
||||||
|
except KeyError:
|
||||||
|
return Response("must have a file as obtained from /upload, in the format ?file=...", status=400)
|
||||||
|
if alnum_regex.match(file) is None:
|
||||||
|
return Response(f"filename '{file}' was not alphanumeric", status=400)
|
||||||
|
return Response(generate_output(file), mimetype="text/event-stream")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/transcribe-ui')
|
||||||
|
def index():
|
||||||
|
return render_template_string(open(index_page_path).read()) # Assuming 'index.html' is in the same directory
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/upload', methods=["POST"])
|
||||||
|
def upload():
|
||||||
|
if 'file' not in request.files:
|
||||||
|
return 'No "file" part in request', 400
|
||||||
|
file = request.files['file']
|
||||||
|
|
||||||
|
# Create temp file for this upload
|
||||||
|
handle, temp_file = tempfile.mkstemp(text=False)
|
||||||
|
try:
|
||||||
|
os.close(handle)
|
||||||
|
file.save(temp_file)
|
||||||
|
# get filename from absolute path
|
||||||
|
temp_file_frag = os.path.basename(temp_file)
|
||||||
|
|
||||||
|
normalize(temp_file, f"/tmp/whisper/{temp_file_frag}")
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.remove(temp_file)
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return Response(temp_file_frag, mimetype="text/plain")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/download')
|
||||||
|
def download():
|
||||||
|
try:
|
||||||
|
file = request.args.get('file')
|
||||||
|
except KeyError:
|
||||||
|
return Response("must have a file parameter", status=400)
|
||||||
|
|
||||||
|
if alnum_regex.match(file) is None:
|
||||||
|
return Response(f"file '{file}' was not alphanumeric, bad format", status=400)
|
||||||
|
|
||||||
|
return Response(open(f"/tmp/whisper/{file}.wav", 'rb').read(), mimetype="audio/wav")
|
||||||
|
|
||||||
|
|
||||||
|
def run(port: int):
|
||||||
|
waitress.serve(app, host="0.0.0.0", port=port)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
normalize_binary = os.environ["WHISPER_NORMALIZE"]
|
||||||
|
whisper = os.environ["WHISPER_CLIENT"]
|
||||||
|
index_page_path = os.environ["INDEX_PAGE_PATH"]
|
||||||
|
ytdlp = os.environ["YT_DLP"]
|
||||||
|
run(int(os.environ["WHISPER_PORT"]))
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -9,10 +9,10 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Nager.PublicSuffix" Version="2.4.0" />
|
<PackageReference Include="Nager.PublicSuffix" Version="2.4.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="Pulumi" Version="3.54.1" />
|
<PackageReference Include="Pulumi" Version="3.59.0" />
|
||||||
<PackageReference Include="Pulumi.Cloudflare" Version="5.2.0" />
|
<PackageReference Include="Pulumi.Cloudflare" Version="5.16.0" />
|
||||||
<PackageReference Include="Pulumi.Command" Version="0.5.2" />
|
<PackageReference Include="Pulumi.Command" Version="0.5.2" />
|
||||||
<PackageReference Include="Pulumi.DigitalOcean" Version="4.19.1" />
|
<PackageReference Include="Pulumi.DigitalOcean" Version="4.24.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -54,6 +54,8 @@
|
|||||||
<Content Include="Nix\puregym\puregym.nix" />
|
<Content Include="Nix\puregym\puregym.nix" />
|
||||||
<Content Include="Nix\puregym\refresh-auth.sh" />
|
<Content Include="Nix\puregym\refresh-auth.sh" />
|
||||||
<Content Include="Nix\puregym\puregym.py" />
|
<Content Include="Nix\puregym\puregym.py" />
|
||||||
|
<Content Include="Nix\whisper\whisper.nix" />
|
||||||
|
<Content Include="Nix\whisper\whisper.py" />
|
||||||
<Content Include="config.schema.json" />
|
<Content Include="config.schema.json" />
|
||||||
<Content Include="waitforready.sh">
|
<Content Include="waitforready.sh">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
Reference in New Issue
Block a user