-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration
The user configuration is TOML at ${XDG_CONFIG_HOME:-$HOME/.config}/voice-input/config.toml. The installed public sample is ~/.local/share/voice-input/config.toml.
Inspect the effective deserialized configuration without credentials:
voice-input config
voice-input config --format jsonAfter editing TOML, restart the daemon:
systemctl --user restart voice-input.serviceThe on-demand Quickshell Settings window exposes the supported configuration and saves a complete, validated configuration through Rust. Its Overview summarizes the local service and current configuration. Speech, Refinement, Output, Appearance, and Hotkey & state group everyday controls, while each relevant page exposes its own expandable Advanced section for technical tuning. Alibaba Realtime and experimental Audio3 options appear inside Speech when the corresponding provider is selected. QML does not parse or write TOML.
voice-input settingsSettings loads the config through a dedicated voice-input settings-backend --stdio child using versioned NDJSON. The same child reports a narrowly allowlisted runtime summary for Overview; it never returns transcript text, output targets, arbitrary runtime errors, or credentials. Rust returns an opaque revision tied to the exact config source it read. Save includes that revision and every supported field; if another editor changed the source, Rust rejects the stale save and asks the user to reload instead of silently overwriting it.
Rust creates the config directory with mode 0700, writes config.toml with mode 0600, and atomically replaces the file. Save can also restart voice-input.service; restart failure is reported separately when persistence has already succeeded. Credential fields support keep or replace only. They are cleared after submission; QML/JavaScript memory clearing is best effort.
| Field | Default | Meaning |
|---|---|---|
state_file |
"auto" |
auto uses the runtime state file. A custom path receives an additional copy. disabled suppresses that optional copy; the daemon still maintains $XDG_RUNTIME_DIR/voice-input/state.json for status/HUD. |
hotkey.accelerator |
", F9" |
Hyprland accelerator text used when generating the primary start/stop binding and when deciding output settle behavior. The daemon does not register a global shortcut itself. |
hotkey.mode |
"toggle" |
hold or toggle. Determines the generated F9-style start/stop binding. In toggle mode, an accelerator containing a modifier forces at least 500 ms of pre-output settling. |
The installed static Hyprland snippet also binds F8 to cancel and F10 to discard and restart, while leaving Omarchy's stock Super+Ctrl+X Voxtype shortcut unchanged. Use voice-input setup hyprland to generate bindings from the current config.
| Field | Default | Meaning |
|---|---|---|
device |
"default" |
PipeWire target. default omits pw-record --target; any other value is passed as the target. |
sample_rate |
16000 |
Capture sample rate and WAV/ASR rate in Hz. Qwen receives this rate in session metadata. |
max_duration_secs |
300 |
Maximum recording length for both dedicated and shared pre-roll capture paths. Reaching the limit automatically stops capture and starts finalization instead of leaving the session recording. |
partial_interval_ms |
1500 |
Sleep interval for repeated local-CLI partial transcription. Realtime Qwen partials are event-driven. |
pre_roll_enabled |
false |
Keeps pw-record open while the daemon runs and seeds a new session from a ring buffer. This has microphone-privacy implications. |
pre_roll_ms |
500 |
Requested pre-roll window. The ring also retains at least the 320 ms capture warm-up. |
| Field | Default | Values / behavior |
|---|---|---|
provider |
"local-cli" |
local-cli, alibaba-qwen-realtime, or the explicitly gated experimental alibaba-qwen-audio3. |
backend_command |
"/usr/bin/voxtype" |
Executable for local final/partial ASR and remote fallback. It receives optional --engine, optional --model, --language CODE transcribe WAV. |
engine |
"sensevoice" |
Local backend engine. An empty value omits --engine. |
model |
"" |
Local backend model. Empty means backend default and omits --model. |
language |
"simplified-chinese" |
english, simplified-chinese, traditional-chinese, japanese, or korean. ASR codes are en, zh, ja, and ko; Chinese variants then use OpenCC. |
connect_timeout_ms |
5000 |
Realtime TCP/WebSocket connection timeout; also the HTTP connect timeout for full-audio passes. Valid range: 100–120,000 ms. Audio3 replacement connections cap this value at 5,000 ms. |
finalize_timeout_ms |
8000 |
Deadline after requesting the realtime provider to finish. Valid range: 100–120,000 ms. |
fallback_to_local |
true |
Allows Qwen failure, empty output, or an incomplete realtime audio stream to call the local backend with the complete recording. A successful realtime transcript can still be used after some worker errors, but never after realtime delivery backpressure made the remote stream incomplete. |
backend_command defaults explicitly to /usr/bin/voxtype. Keep the absolute path to avoid invoking Voice Input recursively.
| Field | Default | Meaning |
|---|---|---|
endpoint |
"wss://dashscope.aliyuncs.com/api-ws/v1/realtime" |
Realtime WebSocket endpoint. The model query parameter is appended if absent. |
model |
"qwen3-asr-flash-realtime-2026-02-10" |
Realtime Qwen model ID. |
turn_mode |
"server-vad" |
server-vad sends VAD settings; manual disables server turn detection and commits on stop. |
vad_threshold |
0.2 |
Server VAD threshold passed unchanged to Qwen. |
silence_duration_ms |
400 |
Server VAD silence duration passed to Qwen. |
final_pass_enabled |
false |
Re-recognizes the complete WAV through the compatible HTTP chat-completions endpoint. |
final_pass_base_url |
"" |
Base URL without /chat/completions. Empty derives the compatible-mode URL for known China, international, or US DashScope realtime hosts. Custom realtime hosts require an explicit value. |
final_pass_model |
"qwen3-asr-flash-2026-02-10" |
Full-audio final model ID. |
final_pass_timeout_ms |
20000 |
Overall HTTP request timeout for the final pass. |
final_pass_enable_itn |
false |
Sends Alibaba asr_options.enable_itn; ITN means inverse text normalization. |
The Alibaba key is not a public TOML field in assets/config.toml. Store credential ID alibaba-api-key as described in Security and Privacy.
Qwen-Audio-3 is opt-in and experimental. It is disabled in the public sample, is not offered by voice-input setup model, and must not be treated as a stable default. Select alibaba-qwen-audio3 in Settings and acknowledge the separate experimental gate before saving. It shares credential ID alibaba-api-key with Alibaba Realtime.
| Field | Default | Meaning |
|---|---|---|
experimental_enabled |
false |
Must be true while asr.provider = "alibaba-qwen-audio3"; selecting the provider does not set the acknowledgement automatically. |
endpoint_mode |
"regional" |
regional uses the reviewed canonical pair for region; custom uses endpoint and native_endpoint exactly. |
region |
"beijing" |
beijing or singapore. In Regional mode this chooses both endpoints. |
endpoint |
"wss://dashscope.aliyuncs.com/api-ws/v1/inference" |
Streaming WebSocket URL. Active only in Custom mode; preserved as dormant data in Regional mode. |
model |
"qwen-audio-3.0-asr-flash-streaming" |
Streaming model ID. |
language_hints_enabled |
false |
Sends hints derived from [asr].language: en; zh,en; ja,en; or ko,en. Disabled preserves provider auto-detection. |
heartbeat_enabled |
false |
Keeps a long silent streaming push-to-talk session alive while valid audio frames continue. It is not sent to Native. |
recognition_preset |
"standard" |
standard, low-latency-dictation, long-form, or custom; see the effective mappings below. |
max_sentence_silence_ms |
800 |
Custom maximum sentence silence. The effective value must be 200–6,000 ms. Named presets use their fixed values and preserve this raw field as dormant data. |
semantic_punctuation_enabled |
false |
Custom semantic-punctuation switch. Named presets use their fixed mapping. |
multi_threshold_mode_enabled |
false |
Custom multi-threshold switch. Named presets use their fixed mapping. |
speech_noise_threshold |
omitted | Optional Custom finite threshold from -1 through 1. Omission leaves provider behavior unchanged. Named presets do not send it. |
vocabulary |
[] |
Global dynamic vocabulary as { term, weight } entries. A nonempty list is sent to both Streaming and Native. |
native_endpoint |
"https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation" |
Native HTTP URL. Active only in Custom mode; preserved as dormant data in Regional mode. |
native_model |
"qwen-audio-3.0-asr-flash" |
Native full-audio model ID. |
native_final_pass_mode |
"streaming-only" |
streaming-only, adaptive, or always; see the policy below. |
native_timeout_ms |
20000 |
Native overall request timeout. Operational range: 100–120,000 ms; validation applies whenever the configured policy can run Native automatically. |
Regional mode resolves to these fixed pairs; it does not combine a Streaming endpoint from one region with a Native endpoint from another:
| Region | Streaming | Native |
|---|---|---|
beijing |
wss://dashscope.aliyuncs.com/api-ws/v1/inference |
https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation |
singapore |
wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference |
https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation |
Custom endpoints must be valid ws/wss and http/https URLs respectively. Non-loopback hosts require encrypted wss/https, embedded credentials are rejected, and the configured strings—including path, port, and query—remain the selected route. Regional mode ignores and preserves dormant Custom URLs.
| Value | Effective controls |
|---|---|
standard |
max_sentence_silence_ms = 800; semantic punctuation off; multi-threshold mode off; no speech/noise threshold. This remains the default. |
low-latency-dictation |
400 ms; semantic punctuation off; multi-threshold mode on; no threshold. It remains an experimental evaluation candidate, not a general recommendation. |
long-form |
1300 ms; semantic punctuation on; multi-threshold mode off; no threshold. It remains an experimental evaluation candidate. |
custom |
Uses all four raw controls. Silence must be 200–6,000 ms; an optional threshold must be finite and within -1..=1; semantic punctuation and multi-threshold mode are mutually exclusive. |
vocabulary is optional. Streaming puts the same trimmed term/weight map in run-task; Native puts it in the full-audio request. Local validation enforces all of the following:
- at most 2,000 entries;
- at most 256 KiB total configured
termbytes; - no control characters and no term that is empty after trimming;
- an all-ASCII trimmed term has at most 7 whitespace-separated segments; any term containing non-ASCII text has at most 15 Unicode characters;
-
weightis1–5or exactly50; - at most 50 entries have weight
50; - terms must be unique after trimming (exact string comparison).
Routine diagnostics report only the entry count, never the terms.
-
streaming-onlynever sends the complete recording automatically. -
adaptiveruns Native when streaming is empty, failed, degraded, interrupted, overloaded, not explicitly finished by the provider, or the recording reaches 30 seconds. It skips only a usable, non-overloaded, explicitly finished stream shorter than 30 seconds. If a healthy completed stream actually sent Audio3 Session Context, duration alone does not replace it with Native; the other recovery reasons still apply. -
alwaysruns Native for every non-cancelled, nonempty recording.
A successful Native transcript takes precedence. On Native failure or timeout, usable Streaming text remains available, followed by local fallback only when needed. Cancellation never launches Native. Native accepts at most 10 MiB of raw WAV bytes.
Migration distinguishes a missing field from an explicitly configured value:
- Without
endpoint_mode, only the exact canonical Beijing or Singapore URL pair enters Regional mode. The matching pair supplies the inferred region unless an explicitregionoverrides it. Every other pair becomes Custom, with both original URL strings preserved byte-for-byte; a missing region then defaults to Beijing. - The removed
workspace_idfield is ignored on load and omitted on save. It has no request or routing effect. - Legacy
native_final_pass_enabled = truebecomesnative_final_pass_mode = "always";falsebecomes"streaming-only". If both old and new fields are present, only matching combinations load; conflicting combinations are rejected as ambiguous. - If
recognition_presetis missing, the legacy raw controls becomestandardonly for the exact default combination (800, both switches false, no threshold). Every other combination becomescustomand retains the raw values.
Alibaba API keys are region-scoped. Voice Input does not migrate a key when the region changes and never probes another region. Replace credential alibaba-api-key yourself when the selected region requires another key. Singapore selection does not imply that every model/control scenario has been live-validated.
The standalone commands below require Audio3 to be selected and explicitly enabled. They upload the WAV to the resolved Regional route or exact Custom endpoint and may incur API charges:
voice-input asr stream-test --file sample.wav
voice-input asr test --file sample.wavThe streaming test requires a 16 kHz mono PCM16 WAV. The Native command applies the 10 MiB raw-WAV limit.
| Field | Default | Meaning |
|---|---|---|
mode |
"paste" |
Text delivery always uses clipboard paste. Legacy type and clipboard values remain parseable for existing config files but no longer change runtime behavior. |
fallback_to_clipboard |
true |
Legacy compatibility field; retained when loading and saving older configurations but no longer changes runtime behavior. |
type_delay_ms |
0 |
Legacy compatibility field; per-character synthetic typing is no longer used. |
pre_type_delay_ms |
140 |
Delay before clipboard output. Toggle shortcuts containing modifiers raise it to at least 500 ms. |
paste_keys |
"shift+Insert" |
Wayland paste chord sent to the active window by Hyprland dispatch sendshortcut. Supported modifiers are Ctrl, Shift, Alt, and Super. |
prefer_paste_for_xwayland |
true |
Legacy compatibility field; XWayland always uses the paste route. |
xwayland_paste_keys |
"shift+Insert" |
XWayland chord sent through xdotool; empty falls back to paste_keys. |
Every output temporarily places recognized text on the target clipboard, sends the paste chord, waits 220 ms, and restores the previous content. On native Wayland, both the transcript and restored payload use the wl-copy --sensitive hint; only compatible clipboard managers guarantee that these items are excluded from history and not reordered. XWayland has no equivalent hint. Backup/restoration is best effort when no readable clipboard content exists.
| Field | Default | Meaning |
|---|---|---|
manage_fcitx5 |
true |
Enables the Fcitx5 guard. |
force_ascii_before_output |
true |
If both flags are true and fcitx5-remote reports state 2, run fcitx5-remote -c before output and -o afterward. |
| Field | Default | Meaning |
|---|---|---|
enabled |
false |
Enables conservative transcript refinement. Failure always keeps the ASR text. |
api_base_url |
"https://api.openai.com/v1" |
OpenAI-compatible base URL; /chat/completions is appended. |
model |
"" |
Required model ID when enabled. |
timeout_ms |
15000 |
Shared refinement budget, clamped to 1,000–30,000 ms. Contextual and transcript-only attempts share it; budgets of at least 10,000 ms reserve the final 5,000 ms for transcript-only recovery. |
provider_sort |
"" |
If non-empty and the URL host is openrouter.ai or a subdomain, sends provider.sort. Ignored for other hosts. |
agent_context_enabled |
false |
Captures terminology once from the validated Pi/Codex session focused when dictation starts. It is effective when either Audio3 or LLM refinement will consume the snapshot; it does nothing when both consumers are absent. |
agent_context_max_chars |
6000 |
Local source-message budget, valid from 500–12,000 characters. Local redaction/truncation happens before consumer-specific selection; this is not the number of characters sent remotely. |
One immutable start-time terminology snapshot is shared by enabled consumers. Audio3 Session Context receives a newline-separated view of at most 400 characters. Refine receives at most 96 terms and 1,500 total term characters. Each consumer therefore applies a smaller bound than agent_context_max_chars; the local source message, term frequencies, window titles, and process metadata are not sent.
The LLM credential uses ID openrouter-api-key, including when api_base_url points to another OpenAI-compatible provider. No key appears in voice-input config output.
| Field | Default | Meaning |
|---|---|---|
enabled |
true |
Controls whether the resident Quickshell HUD surface is shown. The voice-input-hud.service process may remain running while the surface is disabled. |
margin_bottom |
72 |
Bottom margin used by the Quickshell HUD, in logical pixels. |
height |
56 |
Base/minimum capsule height used by the Quickshell HUD, in logical pixels. |
position |
"bottom-center" |
bottom-center, bottom-left, or bottom-right; reflected in state and honored by Quickshell. |
offset_x |
0 |
Horizontal offset in logical pixels. Positive moves right. |
offset_y |
0 |
Vertical offset added to the bottom margin. Positive moves upward. |
nudge_step |
24 |
Default amount for voice-input hud move …; runtime forces at least 1. |
The daemon includes hud_enabled, hud_margin_bottom, hud_height, hud_position, hud_offset_x, and hud_offset_y in every HUD snapshot. Quickshell honors all six values.
Move commands update TOML and runtime state immediately:
voice-input hud move left
voice-input hud move up 10
voice-input hud position bottom-right
voice-input hud center # bottom-center and x=0; preserves y
voice-input hud reset # bottom-center and x=y=0At daemon startup, each secret resolves in this order:
- systemd credential from
$CREDENTIALS_DIRECTORY(alibaba-api-keyoropenrouter-api-key); -
VOICE_INPUT_ALIBABA_API_KEYorVOICE_INPUT_OPENROUTER_API_KEY; - a legacy in-memory TOML value, if present in an older config.
Use encrypted systemd credentials for the supplied service. Environment variables are mainly useful for a manually launched daemon and may be exposed to same-user process inspection.
Settings credential replacement and Test LLM requests send entered secrets only over inherited stdin. Keys are never included in config, process arguments, environment variables, logs, or backend responses. Test LLM can use either a just-entered key or the existing encrypted-store credential.
See also: Security and Privacy · Troubleshooting
English Home · 简体中文首页 · Source repository · MIT License
Voice Input is an independent community project. HUD and Settings require Quickshell 0.3+. Review Security and Privacy before enabling remote ASR, LLM refinement, pre-roll, agent context, or replacing credentials in Settings.
Voice Input 是独立的社区项目。HUD 和 Settings 需要 Quickshell 0.3 或更高版本。启用远程 ASR、LLM refinement、pre-roll、Agent 上下文,或者在 Settings 中替换 credential 前,请阅读安全与隐私。