Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/test-distros.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ jobs:
grep -Fq openwhispr-binds.lua /home/dev/.config/hypr/hyprland.lua
command -v wl-copy
command -v wtype
fish -n /home/dev/.config/fish/functions/asr-mode.fish
fish -c 'source /home/dev/.config/fish/functions/asr-mode.fish; asr-mode --help' | grep -Fq 'asr-mode {sensevoice|qwen-1.7b|off}'
! command -v voxtype
test ! -e /home/dev/.config/voxtype
! id -nG dev | grep -qw input
test ! -e /etc/udev/rules.d/70-uinput.rules
! command -v ydotoold
Expand All @@ -50,6 +54,10 @@ jobs:
grep -Fq openwhispr-binds.lua /home/ubuntu/.config/hypr/hyprland.lua
command -v wl-copy
command -v wtype
fish -n /home/ubuntu/.config/fish/functions/asr-mode.fish
fish -c 'source /home/ubuntu/.config/fish/functions/asr-mode.fish; asr-mode --help' | grep -Fq 'asr-mode {sensevoice|qwen-1.7b|off}'
! command -v voxtype
test ! -e /home/ubuntu/.config/voxtype
! id -nG ubuntu | grep -qw input
test ! -e /etc/udev/rules.d/70-uinput.rules
! command -v ydotoold
Expand All @@ -69,6 +77,10 @@ jobs:
binary="$HOME/.local/libexec/openwhispr/OpenWhispr.app/Contents/MacOS/OpenWhispr"
test -x "$binary"
file "$binary" | grep -q "$(uname -m)"
fish -n "$HOME/.config/fish/functions/asr-mode.fish"
fish -c "source '$HOME/.config/fish/functions/asr-mode.fish'; asr-mode --help" | grep -Fq 'asr-mode {sensevoice|qwen-1.7b|off}'
test ! -e "$HOME/.local/libexec/voxtype"
test ! -e "$HOME/.config/voxtype"

windows:
name: windows:latest
Expand Down
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ chezmoi init --apply collieiscute -v
| `SUPER+C` | close window |
| `SUPER+M` | exit Hyprland |
| `SUPER+V` | toggle floating |
| hold `F13` | Voxtype push-to-talk dictation |
| tap `F13` | OpenWhispr dictation toggle |
| `SUPER+P` | pseudotile |
| `SUPER+RETURN` | true fullscreen |
| `SUPER+N` | toggle Noctalia notifications |
Expand All @@ -105,21 +105,24 @@ chezmoi init --apply collieiscute -v
| `XF86Audio*` | volume / mute / mic mute |
| `XF86MonBrightness*` | screen brightness |

Voice dictation supports Arch Linux x86_64 and Apple silicon macOS. Select
`voxtype-mode sensevoice` for the CPU-only SenseVoice model or
`voxtype-mode qwen-1.7b` for the GPU-backed Qwen3-ASR model; missing models
download only when selected. Run `voxtype-mode off` before gaming to stop and
verify every managed ASR process, releasing the GPU. `voxtype-mode --help`
lists the same commands in Fish.
Voice dictation uses OpenWhispr on Arch Linux x86_64 and macOS. Select
`asr-mode sensevoice` for the CPU-only SenseVoice model or `asr-mode qwen-1.7b`
for the GPU-backed Qwen3-ASR model; missing models download only when selected.
Run `asr-mode off` before gaming to stop CrispASR, close port 8080, and release
its GPU memory. OpenWhispr remains in the tray; quit it separately when its UI
and shortcut are not needed.

Linux uses the Hyprland `F13` binding. On macOS, `F13` is handled by VoxType;
allow Microphone and Accessibility access when macOS prompts for them.
Set OpenWhispr to Self-Hosted `http://127.0.0.1:8080/v1`, model `local-asr`, and
F13 tap mode. Linux uses its native Hyprland binding and `wtype`; macOS requires
Microphone and Accessibility access. OpenWhispr 1.9.2 may still show a ydotool
setup warning on Linux; `wtype` is already preferred, so do not add the `input`
group or daemon just to dismiss it.

### AeroSpace (macOS)

| Bind | Action |
|---|---|
| hold `F13` | Voxtype push-to-talk dictation |
| tap `F13` | OpenWhispr dictation toggle |
| `Cmd+Option+H/J/K/L` | swap workspace windows left/down/up/right, keeping workspace numbers fixed |
| `Cmd+Option+S` | toggle the dedicated `magic` workspace |
| `Cmd+Option+Shift+S` | move window to the `magic` workspace |
Expand Down
1 change: 0 additions & 1 deletion home/.chezmoidata/packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ packages:
- ttf-jetbrains-mono-nerd
- typst
- unzip
- voxtype-bin
- wireplumber
- wget
- wl-clipboard
Expand Down
7 changes: 0 additions & 7 deletions home/.chezmoiexternal.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ include = ["crispasr-linux-x86_64-vulkan/crispasr", "crispasr-linux-x86_64-vulka
checksum.sha256 = "081e814933ab3d1e1b3ab4da46243d6fc8fe9a6cc89d98ae05b0e2157fe59ad6"
checksum.size = 70198311
{{ else if eq .chezmoi.os "darwin" -}}
[".local/libexec/voxtype/voxtype"]
type = "file"
url = "https://github.com/peteonrails/voxtype/releases/download/v0.7.5/voxtype-0.7.5-macos-universal"
executable = true
checksum.sha256 = "12e794655f0e0efadceb92e6313cec2c618c571892490368d0b90194cc27cc6e"
checksum.size = 24338816

[".local/libexec/openwhispr"]
type = "archive"
exact = true
Expand Down
6 changes: 5 additions & 1 deletion home/.chezmoiremove
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
.config/cursor-flags.conf
.config/alacritty/catppuccin-mocha.toml
.config/kitty/themes/catppuccin-macchiato.conf
.config/fish/completions/voxtype-mode.fish
.config/fish/functions/voxtype-mode.fish
.config/fish/functions/voxtype-post-process.fish
.config/voxtype
.local/libexec/voxtype
{{ if eq .chezmoi.os "linux" }}
.config/hypr/hypridle.conf
.config/hypr/hyprlock.conf
Expand All @@ -15,7 +20,6 @@
.config/waybar/themes/frappe.css
.local/bin/dropbox.py
.local/lib/dropbox/dropbox.py
.local/libexec/voxtype
{{ if eq .chezmoi.osRelease.id "arch" }}
.config/noctalia/templates/alacritty.toml
.config/noctalia/templates/ghostty
Expand Down
5 changes: 5 additions & 0 deletions home/dot_config/fish/completions/asr-mode.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
complete -c asr-mode -f
complete -c asr-mode -s h -l help -d 'Show help'
complete -c asr-mode -n 'not __fish_seen_subcommand_from sensevoice qwen-1.7b off' -a sensevoice -d 'SenseVoice Small Q8_0 (CPU)'
complete -c asr-mode -n 'not __fish_seen_subcommand_from sensevoice qwen-1.7b off' -a qwen-1.7b -d 'Qwen3-ASR 1.7B Q8_0 (GPU)'
complete -c asr-mode -n 'not __fish_seen_subcommand_from sensevoice qwen-1.7b off' -a off -d 'Stop CrispASR and release its resources'
5 changes: 0 additions & 5 deletions home/dot_config/fish/completions/voxtype-mode.fish

This file was deleted.

174 changes: 174 additions & 0 deletions home/dot_config/fish/functions/asr-mode.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
function __asr_download_model --argument-names label url file
test -f "$file"
and return

command mkdir -p (command dirname "$file")
or return
echo "Downloading $label..."
command curl --fail --location --retry 3 --output "$file" "$url"
or begin
command rm -f -- "$file"
return 1
end
end

function __asr_stop_managed --argument-names os
if test $os = Linux
command systemctl --user stop crispasr.service \
voxtype-active.service voxtype-asr.service voxtype-qwen.service voxtype.service \
>/dev/null 2>&1
else
for label in com.collie.crispasr com.collie.voxtype.active com.collie.voxtype.asr
command launchctl remove $label >/dev/null 2>&1
or true
end
return
end
or true
end

function asr-mode --description 'Switch CrispASR model or stop ASR'
argparse h/help -- $argv
or return 2

if set -q _flag_help
printf '%s\n' \
'Usage: asr-mode {sensevoice|qwen-1.7b|off}' \
'' \
' sensevoice SenseVoice Small Q8_0 (CPU)' \
' qwen-1.7b Qwen3-ASR 1.7B Q8_0 (GPU)' \
' off Stop CrispASR and verify PID and port 8080 are gone' \
'' \
'OpenWhispr remains running; this command controls CrispASR only.'
return
end

if test (count $argv) -ne 1
echo 'Usage: asr-mode {sensevoice|qwen-1.7b|off}' >&2
return 2
end
set -l mode $argv[1]
contains -- $mode sensevoice qwen-1.7b off
or begin
echo "asr-mode: unknown mode: $mode" >&2
return 2
end

set -l os (uname -s)
contains -- $os Linux Darwin
or begin
echo "asr-mode: unsupported platform: $os" >&2
return 1
end

set -l dependencies curl pgrep
if test $os = Linux
set -a dependencies systemctl
test $mode = off
or set -a dependencies systemd-run
else
set -a dependencies launchctl
end
for dependency in $dependencies
command -q $dependency
or begin
echo "asr-mode: missing $dependency" >&2
return 1
end
end
if test $os = Linux
command systemctl --user show-environment >/dev/null
or begin
echo 'asr-mode: systemd user manager is unavailable' >&2
return 1
end
end

set -l unit crispasr.service
set -l label com.collie.crispasr
set -l health http://127.0.0.1:8080/health
set -l data_home "$XDG_DATA_HOME"
test -n "$data_home"
or set data_home "$HOME/.local/share"
# Reuse the existing models; moving 2.76 GB adds no value.
set -l model_dir "$data_home/voxtype/models"
set -l crisp "$HOME/.local/libexec/crispasr/crispasr"
set -l process_pattern "^"(string escape --style=regex -- "$crisp")"( |\$)"

if test $mode = off
__asr_stop_managed $os
if test $os = Linux
if command systemctl --user is-active --quiet $unit
echo "asr-mode: $unit is still active" >&2
return 1
end
else if command launchctl list $label >/dev/null 2>&1
echo "asr-mode: $label is still loaded" >&2
return 1
end
if command pgrep -u (id -u) -f "$process_pattern" >/dev/null
echo 'asr-mode: CrispASR is still running' >&2
return 1
end
if command curl --fail --silent --max-time 1 "$health" >/dev/null 2>&1
echo 'asr-mode: port 8080 health endpoint is still reachable' >&2
return 1
end
return
end

test -x "$crisp"
or begin
echo 'asr-mode: missing CrispASR; run chezmoi apply' >&2
return 1
end

set -l backend
set -l server_mode
set -l model
switch $mode
case sensevoice
set backend sensevoice
set server_mode -ng
set model "$model_dir/sensevoice-small-q8_0.gguf"
__asr_download_model \
'SenseVoice Small Q8_0 (252 MB)' \
https://huggingface.co/cstr/sensevoice-small-GGUF/resolve/e14d94223aef728879f08dfb4d5f20fe873b22ef/sensevoice-small-q8_0.gguf \
"$model"
or return
case qwen-1.7b
set backend qwen3
set server_mode --gpu-backend vulkan
test $os = Darwin
and set server_mode --gpu-backend metal
set model "$model_dir/qwen3-asr-1.7b-q8_0.gguf"
__asr_download_model \
'Qwen3-ASR 1.7B Q8_0 (2.51 GB)' \
https://huggingface.co/cstr/qwen3-asr-1.7b-GGUF/resolve/674df5d44b50a63e7102a18895ed20e3f91de301/qwen3-asr-1.7b-q8_0.gguf \
"$model"
or return
end

set -l server_cmd "$crisp" --server --backend $backend $server_mode \
--lid-backend off -m "$model" --host 127.0.0.1 --port 8080
__asr_stop_managed $os
if test $os = Linux
command systemd-run --user --quiet --collect --service-type=exec --unit=$unit -- $server_cmd
else
command launchctl submit -l $label -- $server_cmd
end
or return

command curl --fail --silent --retry 30 --retry-delay 1 --retry-connrefused \
--max-time 2 "$health" >/dev/null
or begin
__asr_stop_managed $os
echo 'asr-mode: CrispASR did not become ready' >&2
return 1
end
if not command pgrep -u (id -u) -f "$process_pattern" >/dev/null
__asr_stop_managed $os
echo 'asr-mode: CrispASR process is not running' >&2
return 1
end
end
Loading
Loading