Compare commits
No commits in common. "72d733ba7d2cfe8f04a480f1b7391aae82f00e51" and "d34ce8f4b23ae7f63b316c845d040658b034bd22" have entirely different histories.
72d733ba7d
...
d34ce8f4b2
|
|
@ -1,46 +1,31 @@
|
||||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
# and may be overwritten by future invocations. Please make changes
|
# and may be overwritten by future invocations. Please make changes
|
||||||
# to /etc/nixos/configuration.nix instead.
|
# to /etc/nixos/configuration.nix instead.
|
||||||
{
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
modulesPath,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports =
|
||||||
(modulesPath + "/installer/scan/not-detected.nix")
|
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.initrd.availableKernelModules = [
|
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ];
|
||||||
"xhci_pci"
|
|
||||||
"thunderbolt"
|
|
||||||
"nvme"
|
|
||||||
"usb_storage"
|
|
||||||
"sd_mod"
|
|
||||||
];
|
|
||||||
boot.initrd.kernelModules = [ ];
|
boot.initrd.kernelModules = [ ];
|
||||||
boot.kernelModules = [ "kvm-intel" ];
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
boot.extraModulePackages = [ ];
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
fileSystems."/" = {
|
fileSystems."/" =
|
||||||
device = "/dev/disk/by-uuid/041a9bc5-aae2-44ec-bacf-7f6a08a696f9";
|
{ device = "/dev/disk/by-uuid/041a9bc5-aae2-44ec-bacf-7f6a08a696f9";
|
||||||
fsType = "ext4";
|
fsType = "ext4";
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
fileSystems."/boot" =
|
||||||
device = "/dev/disk/by-uuid/79D1-97BE";
|
{ device = "/dev/disk/by-uuid/79D1-97BE";
|
||||||
fsType = "vfat";
|
fsType = "vfat";
|
||||||
options = [
|
options = [ "fmask=0077" "dmask=0077" ];
|
||||||
"fmask=0077"
|
|
||||||
"dmask=0077"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
swapDevices = [
|
swapDevices =
|
||||||
{ device = "/dev/disk/by-uuid/82b669f5-d624-4a29-bf18-dd8bc453f537"; }
|
[ { device = "/dev/disk/by-uuid/82b669f5-d624-4a29-bf18-dd8bc453f537"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
imports = [
|
imports = [
|
||||||
./direnv.nix
|
./direnv.nix
|
||||||
./discord.nix
|
./discord.nix
|
||||||
./dictation.nix
|
|
||||||
./firefox.nix
|
./firefox.nix
|
||||||
./gpg.nix
|
./gpg.nix
|
||||||
./fzf.nix
|
./fzf.nix
|
||||||
|
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
cfg = config.modules.dictation;
|
|
||||||
hyprlandCfg = config.modules.hyprland;
|
|
||||||
|
|
||||||
models = {
|
|
||||||
"tiny.en" = pkgs.fetchurl {
|
|
||||||
url = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin";
|
|
||||||
hash = "sha256-kh5M+Ghv3Zk9zQgaXaW2w2W/3hFi5ysI11rHUomSCx8=";
|
|
||||||
};
|
|
||||||
"base.en" = pkgs.fetchurl {
|
|
||||||
url = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin";
|
|
||||||
hash = "sha256-oDd5yG3zMjB19eeWyyzlAp8A7Ihp7uP9+4l6/jbG0AI=";
|
|
||||||
};
|
|
||||||
"small.en" = pkgs.fetchurl {
|
|
||||||
url = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin";
|
|
||||||
hash = "sha256-xhONbVjsyDIgl+D5h8MvG+i7ChhTKj+I9zTRu/nEHl0=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
runtimeDeps = with pkgs; [
|
|
||||||
coreutils
|
|
||||||
gnused
|
|
||||||
libnotify
|
|
||||||
pipewire
|
|
||||||
whisper-cpp
|
|
||||||
wtype
|
|
||||||
];
|
|
||||||
|
|
||||||
dictation = pkgs.writeShellScriptBin "dictation" ''
|
|
||||||
PATH=${lib.makeBinPath runtimeDeps}:''${PATH:-}
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
model="${models.${cfg.model}}"
|
|
||||||
|
|
||||||
dir="''${XDG_RUNTIME_DIR:-/tmp}/dictation"
|
|
||||||
mkdir -p "$dir"
|
|
||||||
pidfile="$dir/pid"
|
|
||||||
wav="$dir/clip.wav"
|
|
||||||
|
|
||||||
notify() {
|
|
||||||
notify-send -t 2500 "Dictation" "$1" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
case "''${1:-}" in
|
|
||||||
start)
|
|
||||||
if [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
rm -f "$pidfile" "$wav"
|
|
||||||
notify "Listening..."
|
|
||||||
pw-record --rate 16000 --channels 1 --format s16 "$wav" >/dev/null 2>&1 &
|
|
||||||
pid=$!
|
|
||||||
echo "$pid" > "$pidfile"
|
|
||||||
disown
|
|
||||||
sleep 0.3
|
|
||||||
if ! kill -0 "$pid" 2>/dev/null; then
|
|
||||||
rm -f "$pidfile"
|
|
||||||
notify "Microphone unavailable"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
[ -f "$pidfile" ] || exit 0
|
|
||||||
pid="$(cat "$pidfile")"
|
|
||||||
rm -f "$pidfile"
|
|
||||||
if kill -0 "$pid" 2>/dev/null; then
|
|
||||||
kill -INT "$pid" 2>/dev/null || true
|
|
||||||
for _ in $(seq 1 40); do
|
|
||||||
kill -0 "$pid" 2>/dev/null || break
|
|
||||||
sleep 0.05
|
|
||||||
done
|
|
||||||
kill -0 "$pid" 2>/dev/null && kill -KILL "$pid" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
sleep 0.1
|
|
||||||
|
|
||||||
if [ ! -f "$wav" ]; then
|
|
||||||
notify "Recording missing"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
# Ignore clips shorter than 0.5s (16 kHz, s16, mono: 32000 B/s + 44 B header)
|
|
||||||
size="$(stat -c %s "$wav" 2>/dev/null || echo 0)"
|
|
||||||
if [ "$size" -lt 16044 ]; then
|
|
||||||
rm -f "$wav"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! text="$(whisper-cli -np -nt -t "$(nproc)" -m "$model" -f "$wav" 2>/dev/null \
|
|
||||||
| sed -e 's/([^)]*)//g' -e 's/\[[^]]*\]//g' \
|
|
||||||
| tr '\n' ' ' \
|
|
||||||
| sed -e 's/ */ /g' -e 's/^ *//' -e 's/ *$//')"; then
|
|
||||||
rm -f "$wav"
|
|
||||||
notify "Transcription failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
rm -f "$wav"
|
|
||||||
|
|
||||||
if [ -z "$text" ]; then
|
|
||||||
notify "No speech detected"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
wtype -- "$text" || notify "Could not type transcription"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "usage: dictation {start|stop}" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
home.packages = [ dictation ];
|
|
||||||
|
|
||||||
wayland.windowManager.hyprland = mkIf hyprlandCfg.enable {
|
|
||||||
settings = {
|
|
||||||
bind = [ "SUPER, T, exec, dictation start" ];
|
|
||||||
bindr = [ "SUPER, T, exec, dictation stop" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./discord.nix
|
./discord.nix
|
||||||
./dictation.nix
|
|
||||||
./display.nix
|
./display.nix
|
||||||
./gnomeBoxes.nix
|
./gnomeBoxes.nix
|
||||||
./gpg.nix
|
./gpg.nix
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib;
|
|
||||||
{
|
|
||||||
options.modules.dictation = {
|
|
||||||
enable = mkEnableOption {
|
|
||||||
default = false;
|
|
||||||
description = "Enable hold-to-talk voice dictation (hold SUPER+T)";
|
|
||||||
};
|
|
||||||
model = mkOption {
|
|
||||||
type = types.enum [
|
|
||||||
"tiny.en"
|
|
||||||
"base.en"
|
|
||||||
"small.en"
|
|
||||||
];
|
|
||||||
default = "base.en";
|
|
||||||
description = ''
|
|
||||||
The local Whisper model to use for transcription.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -22,7 +22,5 @@
|
||||||
|
|
||||||
modules.discord.enable = true;
|
modules.discord.enable = true;
|
||||||
|
|
||||||
modules.dictation.enable = true;
|
|
||||||
|
|
||||||
modules.tailscale.enable = true;
|
modules.tailscale.enable = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue