Commit 7d424b30bf58

Vincent Demeester <vincent@sbr.pm>
2026-01-09 15:55:16
feat(niri): add voxtype voice-to-text integration
Add voxtype voice-to-text with Whisper for dictation support: - Keybinding: Super+F3 to toggle recording (push-to-talk) - Auto-detect language (English/French) using multilingual base model - Waybar integration with live status indicator and pulsing animation - Clipboard output mode for maximum reliability - Notifications for recording start/stop and transcription complete - Daemon auto-starts with niri compositor Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 2fb85be
Changed files (3)
dots
.config
home
common
dots/.config/niri/config.kdl
@@ -84,6 +84,7 @@ spawn-at-startup "waybar"
 // FIXME should be through systemd
 spawn-at-startup "yubikey-agent" "-l" "/run/user/1000/yubikey-agent/yubikey-agent.sock"
 spawn-at-startup "swaybg" "-i" "/home/vincent/desktop/pictures/lockscreen"
+spawn-at-startup "voxtype" "daemon"
 
 prefer-no-csd
 
@@ -184,6 +185,7 @@ binds {
     Mod+Control+Alt+Return hotkey-overlay-title="Open Emacs Anywhere" { spawn "emacsclient" "-eval" "(vde/type)"; }
     Mod+D hotkey-overlay-title="Run an Application" { spawn "fuzzel"; }
     Mod+Shift+D hotkey-overlay-title="Run Raffi" { spawn "raffi" "-I"; }
+    Mod+F3 hotkey-overlay-title="Voice-to-text (Push-to-talk)" { spawn "voxtype" "record" "toggle"; }
     // FIXME do not use nix run, but needs niri configuration
     Mod+Control+D hotkey-overlay-title="Emoji picker" { spawn "rofimoji" "--selector" "fuzzel" "--clipboarder" "wl-copy" "--typer" "wtype" "--action" "type" "copy"; }
     Mod+Control+V hotkey-overlay-title="Clipboard History" { spawn "bash" "-c" "cliphist list | fuzzel --dmenu --width=100 --lines=20 | cliphist decode | wl-copy"; }
home/common/desktop/niri/default.nix
@@ -15,6 +15,10 @@
     wtype
     wlprop
 
+    # Screenshots and screen recording
+    grim
+    slurp
+
     zenity
     wofi
     rofimoji
@@ -44,48 +48,42 @@
   };
 
   # Voxtype configuration (voice-to-text with Whisper)
+  # Keybinding is handled by niri (Mod+F3 -> voxtype record toggle)
   xdg.configFile."voxtype/config.toml".text = ''
+    # Enable state file for status monitoring (Waybar integration)
+    state_file = "auto"
+
     [hotkey]
-    enabled = true
-    # F13 key - available on moonlander and corne keyboards
-    # For laptops, can be mapped via kanata or similar tools
-    key = "F13"
+    # Hotkey handling is done by niri compositor
+    enabled = false
 
     [audio]
+    # Audio input device ("default" uses system default)
+    device = "default"
+    # Sample rate in Hz (whisper expects 16000)
+    sample_rate = 16000
+    # Maximum recording duration in seconds (safety limit)
+    max_duration_secs = 60
     # Silence threshold in dB - adjust if needed
     silence_threshold = -30.0
 
     [whisper]
-    # "base" model balances speed and accuracy
-    # Options: tiny, base, small, medium, large
+    # Model to use for transcription
+    # Using multilingual model for auto-detection (en/fr)
     model = "base"
+    # Language for transcription ("en" for English, "auto" for auto-detection)
+    language = "auto"
+    # Translate non-English speech to English
+    translate = false
 
     [output]
-    # Use wtype for Wayland text input
-    mode = "type"
+    # Use clipboard mode - more reliable than typing
+    mode = "clipboard"
+
+    [output.notification]
+    # Enable notifications for recording events
+    on_recording_start = true
+    on_recording_stop = true
+    on_transcription = true
   '';
-
-  # Voxtype systemd service
-  systemd.user.services.voxtype = {
-    Unit = {
-      Description = "Voxtype - Push-to-talk voice-to-text daemon";
-      Documentation = "https://voxtype.io/";
-      After = [ "graphical-session.target" ];
-      PartOf = [ "graphical-session.target" ];
-    };
-
-    Service = {
-      Type = "simple";
-      ExecStart = "${pkgs.wip.voxtype}/bin/voxtype daemon";
-      Restart = "on-failure";
-      RestartSec = 5;
-      Environment = [
-        "PATH=${pkgs.wtype}/bin"
-      ];
-    };
-
-    Install = {
-      WantedBy = [ "graphical-session.target" ];
-    };
-  };
 }
home/common/desktop/niri/waybar.nix
@@ -15,6 +15,8 @@ _: {
           "clock"
         ];
         "modules-right" = [
+          "custom/voxtype"
+          "custom/separator"
           "niri/language"
           "custom/separator"
           "wireplumber"
@@ -96,6 +98,12 @@ _: {
           "on-click-right" = "niri msg action switch-layout prev";
           "on-click" = "niri msg action switch-layout next";
         };
+        "custom/voxtype" = {
+          "exec" = "voxtype status --follow --format json";
+          "return-type" = "json";
+          "format" = "{}";
+          "tooltip" = true;
+        };
       };
     };
     style = ''
@@ -210,6 +218,33 @@ _: {
       #custom-separator {
         margin: 0 1px;
       }
+
+      #custom-voxtype {
+        padding: 0 10px;
+      }
+
+      #custom-voxtype.recording {
+        color: #ff5555;
+        animation: pulse 1s ease-in-out infinite;
+      }
+
+      #custom-voxtype.transcribing {
+        color: #f1fa8c;
+      }
+
+      #custom-voxtype.idle {
+        color: #50fa7b;
+      }
+
+      #custom-voxtype.stopped {
+        color: #6272a4;
+      }
+
+      @keyframes pulse {
+        0% { opacity: 1; }
+        50% { opacity: 0.5; }
+        100% { opacity: 1; }
+      }
       		'';
   };
 }