Push-to-talk voice input for fcitx5 — hold a key, speak, release, and the text lands at your cursor.
Nextless is a Typeless-style dictation tool for Linux desktops (Wayland and X11), built as a native fcitx5 add-on. It is a fork of xander-lin/vinput reworked around one idea: the trigger key is yours to choose — including bare modifiers like Right Ctrl — and nothing else about your keyboard behaviour changes.
中文说明 · Roadmap · Contributing · Changelog · Security · Attribution
hold Right Ctrl speak release
─────────────────────────────────────────────────▶ your text, at the cursor
Nextless is the Linux (Ubuntu-first) answer to the "advanced input suite" that Windows and macOS users get for free — voice is the entry point, not the whole story.
The project is done when a Linux user can:
- install it with one command, and uninstall it without leaving debris behind;
- dictate immediately — model, sounds and a sane trigger key already in place, nothing to fetch by hand;
- make it theirs — trigger key, ASR backend, denoiser and notification sounds are all user-swappable; being hackable is the reason this fork exists;
- trust it — every commit is built by CI, the failure paths have tests, and no error ever lands in the document.
Today that is a voice-first fcitx5 add-on. The direction is to close the remaining gaps of a real input suite on Linux: punctuation and polish on top of offline recognition, a first-run experience, real packages, and comfortable coexistence with the typing side of the desk (the Chinese IME you already use). Non-goals: writing another input-method engine, or running a cloud service of our own.
Linux has plenty of speech-to-text, but very little dictation that stays out of your way:
| Typeless / Wispr Flow | openless | Electron dictation apps | Nextless | |
|---|---|---|---|---|
| Platforms | macOS / Windows | macOS / Windows | cross-platform | Linux (Wayland + X11) |
| Trigger | configurable | configurable | global shortcut, no left/right split | any key, incl. Right Ctrl / Alt / Super |
| Works in every app | yes | yes | via simulated typing | yes — it is the input method |
| Offline backend | no | no | some | yes (sherpa-onnx) |
| Background daemon | yes | yes | yes | no |
| Audio normalisation + denoise + VAD | yes | varies | varies | yes |
Because Nextless is an fcitx5 module, it commits text through the input-method path your
browser, editor and terminal already use. No accessibility permission, no xdotool, no
clipboard round-trip, no focus stealing.
- Configurable push-to-talk key.
fcitx5-configtool → Addons → Nextless → Hotkey, or edit~/.config/fcitx5/conf/nextless.conf. Bare modifiers are allowed (Left/Right Ctrl, Alt, Shift, Super) and combos (Ctrl+Alt+A) work too. A short tap is ignored, so the key keeps typing normally; holding it for 300 ms (tunable) starts dictation. - CapsLock still supported, harmlessly. If you pick CapsLock, Nextless re-releases it through
/dev/uinputso the lock state never flips. For any other key no virtual keyboard is created at all. - Five ASR backends, one hot-swap gesture. Two fully offline (Zipformer bilingual, FireRed ASR2 int8) via sherpa-onnx, two cloud (Doubao Streaming ASR 2.0, Qwen3-ASR) and a mock for testing. Switch with Shift+trigger and ←/→; switch denoiser with ↑/↓.
- A real audio pipeline, not a raw mic dump: PulseAudio capture → EBU R128 loudness normalisation (−16 LUFS) → denoising (speexdsp by default, DeepFilterNet3 if you install it) → VAD silence trimming with a retained tail so the last syllable is never clipped.
- Audible state changes. Starting, stopping and switching backend each get a short sound, so
you never have to look at the panel to know the key took effect. Drop your own
activate.wav,deactivate.wavorswitch.wavinto~/.local/share/nextless/sounds/to replace them; they are generated bytools/gen_sounds.py. - Ordering you can trust. You can start the next dictation while the previous one is still being recognised. Each result is bound to the window and input context that was focused when that recording started, and commits happen in recording order (up to three in flight).
- Your mishearings are fixable.
~/.config/nextless/hotwords.jsonmaps what the model heard to what you meant ({"LIBR": "礼拜二"}). The table post-processes the final text of every backend, local and cloud, before punctuation: longest match wins, replacements never chain, and a missing, empty or malformed file changes nothing. Editing it takes effect on the next utterance — no restart. - Errors stay out of your document. Network, service, timeout and microphone failures appear as input-panel status text, never as inserted characters. Silence is a no-op: hold the key, say nothing, release — nothing is committed and nothing is reported.
- Local punctuation is a separate, opt-in model. With the ct-transformer
model installed (
nextless-get-models --punctuation, ~62 MB), Zipformer and FireRed results come out with ,。? automatically — measured ≈ 0.19 s per 44-character utterance on an i7-1260P, on the recognition thread, never the keypress path. If the model is missing or the punctuation run fails, the raw text is committed instead: the decoration step can never eat an utterance. A binary that fails three times in a row is dropped for the rest of the session (same rule as DeepFilterNet), so a broken or quarantined model costs one slow sentence, not five seconds per sentence forever. Doubao still has richer punctuation plus ITN and its own server-side hotwords (different from the localhotwords.jsoncorrection table, which every backend goes through). - The correction table is literal.
hotwords.jsondoes byte-exact replacement — no word segmentation, case-sensitive, no inflection awareness. Two ways of mishearing one word means two entries. - Chinese/English mixed speech is workable on Zipformer bilingual but imperfect on dialect and proper nouns; FireRed is noticeably better and slower.
- Local models are not shipped. You download them yourself (~360 MB or ~1.2 GB, see below).
- The
.debis published on the GitHub Releases page (with sha256sums, andtools/install-deb.shwraps the one-command install); CI builds + installs + removes it on every PR. There is still no apt repository, andfcitx5-nextless-gitis not in the AUR yet (issue #35). amd64 is the only prebuilt arch.
- Linux, fcitx5 ≥ 5.1, PulseAudio (PipeWire's Pulse compatibility is fine — tested on PipeWire 1.x)
- Any desktop: GNOME / KDE / Hyprland, Wayland or X11. A working microphone input.
- Dictation languages follow the model you pick: the bundled defaults cover Chinese, English and zh-en mixed speech.
Arch — build the provided PKGBUILD: makepkg -si (produces fcitx5-nextless-git).
Debian / Ubuntu — one command; it downloads the .deb from the latest GitHub
Release, verifies the sha256, and lets apt resolve every dependency (fcitx5 included):
curl -fsSL https://raw.githubusercontent.com/RevolutionLA/nextless/main/tools/install-deb.sh | sudo bashThe script ends by printing the two steps it will not do for you: nextless-get-models --zipformer --punctuation (models are deliberately not in the .deb) and fcitx5 -r -d.
Before installing it stops if it cannot match the .deb against the release's
sha256sums.txt — an unreachable digest file or an unlisted asset is what a tampered
publish looks like, so that path needs an explicit opt-in:
... | sudo bash -s -- --allow-unverified. amd64 only; other architectures build the
package themselves:
sudo apt install -y build-essential dpkg-dev debhelper git
git clone https://github.com/RevolutionLA/nextless.git
cd nextless
sudo apt build-dep ./ # the dependency list comes from debian/control, not from this README
dpkg-buildpackage -us -uc -b # without -d, so that list is checked before building
sudo apt install ../fcitx5-nextless_*.deb && fcitx5 -r -d# Debian / Ubuntu
sudo apt install -y g++ meson ninja-build git \
libfcitx5core-dev libfcitx5config-dev libfcitx5utils-dev fcitx5-modules-dev \
libpulse-dev libebur128-dev libcurl4-openssl-dev libspeexdsp-dev libsoxr-dev
# Package names above verified with apt-cache on Ubuntu 26.04. There is no libfcitx5-dev
# meta package in the Ubuntu archive; Debian testing/sid names look the same but are
# unverified — please open an issue if they differ.
# Fedora: dnf install gcc-c++ meson ninja-build pkgconf-pkg-config fcitx5-devel libpulse-devel \
# libebur128-devel libcurl-devel speexdsp-devel soxr-devel (not CI-verified yet)
git clone https://github.com/RevolutionLA/nextless.git
cd nextless
meson setup build --prefix=/usr --buildtype=release
ninja -C build
sudo meson install -C build
meson.buildsetswarning_level=2withwerror=true, and CI builds with exactly that, so any new-Wall/-Wextrawarning fails the build. Locally you can drop it withmeson configure build -Dwerror=falsewhile experimenting.-Wpedanticis deliberately not enabled: fcitx5's ownFCITX_CONFIGURATION/FCITX_DECLARE_PRIVATEmacros expand to an "extra;" that GCC flags on the fcitx5 versions distros package (and the fcitx5 headers are pulled in as system includes for the same reason). That is not our bug to fix.
The manifest installs to /usr/share/fcitx5/addon/nextless.conf with OnDemand=False, so
restarting fcitx5 is enough — no need to add Nextless to an input-method list, it is a module,
not a method.
fcitx5 -r -d # replace the running instance; or log out and back infcitx5-configtool → Addons → Nextless → Push-to-talk key, or:
mkdir -p ~/.config/fcitx5/conf
cat > ~/.config/fcitx5/conf/nextless.conf <<'EOF'
[Hotkey]
0=Control_R
DefaultProvider=zipformer
EOF
fcitx5 -r -dnextless-get-modelsThat is the whole step. The helper (installed next to the addon; tools/get_models.sh
in the repo if you want to run it before installing) detects the CPU architecture, shows
the download size before fetching anything, and lets you pick Zipformer, FireRed, or both
(--backend=...; with no terminal it asks for that flag instead of assuming you wanted
the biggest option). It writes only inside ~/.local/share/nextless/, is safe to re-run —
already-installed pieces are skipped — checks every archive against a pinned sha256
before extracting it, and only moves an archive into place after verifying the extracted
directory names are the ones advanced.json expects, so a corrupt or substituted download
leaves no half-extracted model behind. --dry-run prints the plan without touching
anything, and --punctuation also fetches the optional ~62 MB ct-transformer model that
gives the local backends ,。? (an interactive run asks; see Limitations) —
it refuses to proceed if the pinned sherpa-onnx runtime stops shipping the punctuation
binary, rather than installing a config that silently no-ops.
Manual path, if you would rather do it yourself:
mkdir -p ~/.local/share/nextless/sherpa-onnx ~/.local/share/nextless/models
cd /tmp
# sherpa-onnx runtime (shared build: copy bin/ *and* lib/ — the binaries use rpath $ORIGIN/../lib)
# aarch64: the asset name is ...-linux-aarch64-shared-cpu.tar.bz2 (plain -shared is a 404)
V=1.13.8
curl -LO "https://github.com/k2-fsa/sherpa-onnx/releases/download/v${V}/sherpa-onnx-v${V}-linux-x64-shared.tar.bz2"
tar xf "sherpa-onnx-v${V}-linux-x64-shared.tar.bz2"
cp -r "sherpa-onnx-v${V}-linux-x64-shared/"{bin,lib} ~/.local/share/nextless/sherpa-onnx/
# ASR models land under ~/.local/share/nextless/models/<archive-dir>/
M=https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models
mkdir -p ~/.local/share/nextless/models
# Zipformer bilingual zh-en (streaming transducer, ~360 MB of fp32 files)
curl -LO "$M/sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2"
tar xf sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2 -C ~/.local/share/nextless/models/
# FireRed ASR2 int8 (offline AED, ~1.2 GB, more accurate, slower)
curl -LO "$M/sherpa-onnx-fire-red-asr2-zh_en-int8-2026-02-26.tar.bz2"
tar xf sherpa-onnx-fire-red-asr2-zh_en-int8-2026-02-26.tar.bz2 -C ~/.local/share/nextless/models/
rm -f sherpa-onnx-*.tar.bz2Both extractions create the directory names the built-in defaults expect, so there is nothing to
rename. Different paths can be set in ~/.config/nextless/advanced.json.
If the runtime or a model file is missing when you dictate, the input panel says which piece is
missing and tells you to run nextless-get-models — instead of a bare spawn failed /
recognition failed. The exact path it looked for goes to the fcitx5 log.
Cloud backends need no models — just credentials:
mkdir -p ~/.config/nextless
echo '{"api_key":"<your Volcengine APP Key>","resource_id":"volc.seedasr.auc"}' > ~/.config/nextless/doubao.json
echo '{"api_key":"<sk-...>"}' > ~/.config/nextless/qwen.json
chmod 600 ~/.config/nextless/*.jsonspeexdsp ships with the build, and it is enough for a quiet room. For a noisy one you can hand
Nextless the deep-filter CLI from
DeepFilterNet — it is deliberately not a build
dependency, because it is a separate Rust binary carrying its own model:
mkdir -p ~/.local/share/nextless/bin
# whichever you have: a `pip install deepfilternet` binary on PATH, or the
# release asset - the x86_64 musl one is a single 36 MB static binary with the
# model compiled in (no tarball; `deep-filter --version` prints deep_filter 0.5.6),
# so `chmod +x` it and symlink that path directly instead of using command -v.
ln -s "$(command -v deep-filter)" ~/.local/share/nextless/bin/deep-filterAny location works as long as you point at it, either with the path above or with
NEXTLESS_DEEP_FILTER=/usr/bin/deep-filter in the fcitx5 environment. Turn it on with
Shift+trigger and ↑/↓ (persisted to ~/.config/nextless/audio.json).
Nextless resamples to 48 kHz for the model and back to 16 kHz for the recogniser. Because the
denoiser is an external process, it is treated as untrusted: if the binary is missing, exits with
an error, wedges (killed after 5 s) or hands the audio back unchanged, that utterance falls back
to speexdsp instead of losing your words — and after three failures in a row DeepFilterNet is
switched off for the rest of the session. meson test covers all four cases.
What it costs, measured with the real binary on a 2022 i7-1260P
(docs/benchmarks.md): ≈1.0–1.3 s per utterance of 5–10 s speech
(RTF 0.13–0.16 across three runs, ~60 MB) versus single-digit milliseconds for speexdsp. The
process is spawned per utterance, so that second lands between releasing the key and the first
character, and the 5 s deadline stays clear up to well past 30 s of continuous speech. It is also not lossless
in the way the bullet above promises: deep-filter hands back 30 ms less than it receives, so
Nextless appends the last 30 ms of your raw audio to keep the utterance whole — those final
30 ms are un-denoised, but nothing is cut off
(issue #61, fixed; before that the round trip
dropped 69–97 ms off the end). speexdsp stays the default because it costs single-digit
milliseconds rather than a second per utterance and never touches the audio length.
apt remove fcitx5-nextless does not touch fcitx5 itself, so your other input methods
(typing-side IMEs, pinyin) stay exactly where they were. One caveat: if nothing else on the
machine depends on fcitx5, a later apt autoremove can offer to take it away too - read the
list before saying yes.
Installed from the .deb - the three paths named below are exactly what CI's
.deb installs clean job asserts are gone after removal, so this is not a guess:
sudo apt remove fcitx5-nextless # the addon .so, nextless-get-models and nextless.conf go
sudo apt purge fcitx5-nextless # ...and the /etc/nextless defaults too
fcitx5 -r -d # reload without itremove deliberately leaves the /etc/nextless/*.json conffiles behind (dpkg reports
deinstall ok config-files), which is what you want if you mean to reinstall.
To go back to an older release instead - the reason install-deb.sh exists is that a new
version can be the broken one:
sudo dpkg -i fcitx5-nextless_0.3.1-1_amd64.deb # exactly this version, downgrade includedInstalled with meson install - meson has no uninstall, but it wrote the manifest for you:
grep -v '^#' build/meson-logs/install-log.txt | sudo xargs -d '\n' rm -f --Run that from the checkout and build directory you installed from: the log holds absolute
paths recorded at install time, so if you reconfigured with a different --prefix since, it no
longer describes your system. It removes files, not the empty directories they leave behind.
Neither route touches anything in your home, because those are your files, not the package's:
| path | what lives there | size on a typical box |
|---|---|---|
~/.config/nextless/ |
your settings, including any API keys | ~30 KB |
~/.local/share/nextless/models/ |
the downloaded ASR + punctuation models | ~1.8 GB |
~/.local/share/nextless/bin/deep-filter |
the optional denoiser, if you installed it | ~35 MB |
~/.config/autostart/org.fcitx.Fcitx5.desktop |
fcitx5 autostart, only if you added it | 1 KB |
Delete ~/.config/nextless/ before handing a machine over. Deleting the models directory is the
only way to get the 1.8 GB back, and nextless-get-models will re-download whatever is missing.
Check what is actually loaded, because a stale install is otherwise invisible:
fcitx5-diagnose | grep -i nextless # e.g. "Nextless 10.12.0"If that prints an older version than the release you installed, the running addon is the old one -
either the install step did not run, or fcitx5 was never restarted. That is how a machine already
bumped to 0.3.x kept advertising Nextless 0.2.0.
| Action | Keys |
|---|---|
| Dictate | hold your trigger key → speak → release |
| Switch ASR backend | hold Shift + trigger, then ← / → |
| Switch denoiser | hold Shift + trigger, then ↑ / ↓ |
While dictating, the input panel beside the cursor shows listening → processing audio → recognizing → text. Releasing the key returns control to fcitx5 immediately; recognition runs
asynchronously.
| Provider | Type | Disk | Model | Notes |
|---|---|---|---|---|
zipformer |
local | ~360 MB | sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20 |
harness-measured: warm RTF ≈ 0.37, first result ≈ 2.3 s for ~5 s audio, peak RSS ~0.5 GB (i7-1260P; docs/benchmarks.md) |
fire_red |
local | ~1.2 GB | sherpa-onnx-fire-red-asr2-zh_en-int8-2026-02-26 |
harness-measured: warm RTF ≈ 0.82, first result ≈ 6.1 s, peak RSS ~1.6 GB, clearly better on dialects and long sentences (docs/benchmarks.md) |
doubao |
cloud | — | Doubao Streaming ASR 2.0 | punctuation, ITN and server-side hotwords; needs an API key |
qwen |
cloud | — | Qwen3-ASR-Flash | needs an API key |
mock |
test | — | — | returns hello world; useful for verifying the key/capture path |
The hotwords.json correction table applies to all of them — it rewrites the final text
after whichever backend produced it. What is not wired is per-model biasing (sherpa-onnx's
--hotword decode hook on Zipformer); the correction table currently covers proper nouns and
homophones instead.
Both local backends spawn one sherpa-onnx process per utterance on purpose: no resident model
server, no orphan process, no warm-up state to leak. (The systemd/ units in this repo are an
experimental resident-server path and are not required.)
Almost everything is set through the fcitx5 add-on config panel (Fcitx5 Configuration → Add-ons → Nextless → Configure): the push-to-talk key, default provider, activation/notification/debounce timing, denoiser, local model dirs & threads, punctuation toggle, and cloud API keys. Saving there writes the JSON files below in place (preserving any key the panel does not own) and pushes the new values into the running provider, so changes take effect the moment you save — no restart, no hand-editing. The files are still the single source of truth and safe to edit directly; on next load the panel reflects them.
| File | Purpose |
|---|---|
~/.config/fcitx5/conf/nextless.conf |
trigger key ([Hotkey]), DefaultProvider (fcitx5's own store for the two native add-on options) |
~/.config/nextless/nextless.json |
activation_msec (default 300), notification timeout, debounce |
~/.config/nextless/audio.json |
denoise: none | speexdsp | deepfilter |
NEXTLESS_DEEP_FILTER (env) |
path to a system deep-filter binary, overrides the bundled location |
~/.config/nextless/advanced.json |
model dirs, num_threads, timeouts, LUFS target, VAD thresholds |
~/.config/nextless/hotwords.json |
mishearing correction table {"what it heard": "what you meant"}, applied to every backend's final text |
~/.config/nextless/doubao.json / qwen.json |
API credentials |
~/.local/share/nextless/sounds/ |
optional replacements for the bundled activate / deactivate / switch sounds |
meson install ships the config/*.json.example files (renamed to *.json) into the build's
sysconfdir/nextless — /etc/nextless for distro builds (the PKGBUILD passes --sysconfdir=/etc,
and prefix=/usr alone already resolves there), /usr/local/etc/nextless for a plain source
install. The runtime reads that same directory, compiled in: user files win, and a missing user
file is copied from the packaged directory on first read. The packaged hotwords.json is a
placeholder template — keys starting with YOUR_ are dropped when it is parsed, so the copy can
never rewrite real speech until you add entries yourself.
meson setup build --buildtype=debug
ninja -C build
meson test -C build # 21 unit tests: registry, config fallback, capture, queue, silence, cancellation, denoise, missing components, capture-dir sweep, punctuation, hotwords, get_models contract, CER/WER normaliser, panel JSON patcher, installer digest gate, denoise-benchmark row contractTests need a PulseAudio server (the capture tests open a real stream); on a headless runner
pulseaudio --start plus pactl load-module module-null-sink is enough — that is what CI does.
docs/nextless/— design notes: interaction model, ASR provider API, failure analysis.docs/fcitx5/— a short primer on the fcitx5 add-on and configuration system, since Nextless hooks key events atPreInputMethodphase.FINDINGS.md— the measurement log behind the tuning numbers (buffer sizes, model latency, denoiser comparisons). Kept because it explains why defaults are what they are.tools/— standalone harnesses:record_test,calibrate_silence,tail_loss_test,uinput_key(inject a synthetic key hold so you can self-test push-to-talk without typing),gen_sounds.py(regenerate the bundled notification sounds).
Diagnostics (one JSON object per line, no audio and no recognised text) are opt-in:
meson configure build -Ddiagnostic_logging=true && ninja -C build
~/.local/share/nextless/diagnostic.logNextless is a fork of vinput by xander-lin (MIT), which it thanks for the audio pipeline, provider abstraction and the ordering/queue design. The fork adds:
feat(hotkey): trigger key moved from a hardcodedCapsLockto an fcitx5KeyListOption, default Right Ctrl, with/dev/uinputrevert enabled only when the trigger is a locking key- rename to Nextless: add-on/library/config/data paths (
~/.config/nextless,~/.local/share/nextless) fix(defaults): local ASR thread count derived from the CPU instead of a hardcoded 30, and the default Zipformer model directory now matches the real sherpa-onnx archive name
License: MIT — see LICENSE, which retains the upstream copyright notice.
Active work is tracked as GitHub Issues; the list below is the direction, not the queue.
Each item has a finish line, so whoever picks it up knows when it is done.
| Item | Done when | |
|---|---|---|
| 1 | CI is red: cloud_provider_queue fails in the debug job. The provider's error callback fires before the temp WAV is removed (the deletion lives in a scope guard), so the test's exists() check races cleanup — release passes by luck. Fixed in #10 — all four providers now delete the WAV before the callback (caught intermittently by CI's debug job; local reproduction under taskset -c 0 is probabilistic, ~5% on the old code). |
✅ CI is green in both build types; the fix is stronger than this finish line — callback-then-cleanup is now illegal, so the assertion stays strict instead of tolerating it |
| 2 | /etc/nextless defaults are never installed: the config loader reads them and copies them into ~/.config/nextless/ on first use, but no install rule ships them, so every source install silently runs on compiled-in defaults. Fixed in #11 — meson installs the examples as *.json into the build's sysconfdir/nextless and compiles the same path into the loader, so install and read cannot drift; CI does a staged install and fails if any packaged example stops landing (six since hotwords.json). |
✅ meson ships them — /etc/nextless for distro builds (--sysconfdir=/etc), /usr/local/etc/nextless for a plain source install, the same path the loader reads |
| 3 | First run without models or binaries: a missing sherpa-onnx runtime or model currently surfaces as Zipformer: spawn failed / recognition failed, with no hint of what to download. Fixed in #12 — providers pre-check the runtime and each model file and report the exact path; the panel shows "sherpa-onnx runtime missing" / "offline model missing" with the README pointer (test_missing_components drives all four paths against a fake $HOME). |
✅ the input panel names the piece and points at the README's download section; the exact path it looked for goes to the fcitx5 log (and feeds the wizard below) |
| 4 | Real install and removal path: the .deb half is Fixed in #34 (packaging, dependency list, install/purge assertions in CI) and #38 (published on Releases with sha256sums.txt, tools/install-deb.sh one-command route, fail-closed digest check in #51); model fetch is nextless-get-models (#5). Rollback is now documented (README "Rolling back": apt remove vs purge, downgrading with dpkg -i, the meson install-log manifest, and fcitx5-diagnose as the version check), and remove/purge debris checks run in CI. Still open: a human dictating one sentence on a clean Ubuntu VM. AUR is #35. |
VM install ✅ in CI, dictate-on-VM ⏳ needs a person, apt remove leaves no debris ✅, rollback documented ✅ |
| 5 | DeepFilterNet has never run for real: the tests drive it with stub binaries, so one-shot deep-filter cost per utterance is unmeasured. Measured 2026-10-11 with BACKENDS="deepfilter" tools/benchmark/run_bench.sh against deep_filter 0.5.6 — 7/7 utterances (4.7–10 s), 1.0–1.3 s each, RTF 0.13–0.16, 60 MB child RSS. The option stays, and the same run found and fixed issue #61 (the denoiser had been dropping 69–97 ms off the end of every take). |
✅ docs/benchmarks.md carries the row plus the committed machine header and raw JSONL |
| 6 | Coexistence with the typing-side IME: document the supported combinations (wetype, fcitx5 pinyin) and the key-collision rules. | a short doc plus one smoke test per combination |
The longer-term list:
- Local punctuation: integrate
sherpa-onnx-offline-punctuation(ct-transformer) - Hotwords / custom phrases:
~/.config/nextless/hotwords.jsoncorrection table for every backend (per-model biasing still open) - First-run wizard that downloads the right sherpa-onnx build (x86_64 / aarch64) —
nextless-get-models -
.debpackaging: built in CI, published on GitHub Releases withsha256sums.txt, and installed by one command — Fixed in #34 (packaging) and #38 (publishing +tools/install-deb.sh) - An apt repository, so upgrades arrive through
apt upgradeinstead of re-running the installer -
fcitx5-nextlessin the AUR — tracked as #35 - A/B benchmark harness publishing CER / latency / RTF / RSS per model
(
tools/benchmark/+ docs/benchmarks.md; CER rows still need verified transcripts — recording one's own corpus is documented) - Voice cloning / per-user correction learning — undecided, see the discussion thread first
- CI: build × test matrix on GCC with
-Dwerror=true, plus a diagnostics build - Silence is a no-op — no
ASR error: empty result, and FireRed's<sil>never reaches the document - Notification sounds ship with the package (
tools/gen_sounds.pyregenerates them) - DeepFilterNet3 as an opt-in denoiser, with a bounded subprocess and a speexdsp fallback
- Chinese documentation (
README.zh.md)