Files
hyprvoice/docs/config.md
T

20 KiB

Configuration Reference

This document covers manual configuration of hyprvoice via the config.toml file. For most users, the interactive wizard is recommended:

hyprvoice onboarding

To adjust settings later:

hyprvoice configure

Configuration is stored in ~/.config/hyprvoice/config.toml and changes are applied immediately without restarting the daemon.

Onboarding vs Configure

  • hyprvoice onboarding: guided first-time setup for provider keys, voice model, language/streaming, LLM post-processing, keywords, and notifications. Advanced settings stay at defaults.
  • hyprvoice configure: full TUI menu for all sections, including advanced recording, injection backends, timeouts, and notification messages.

Table of Contents

Hyprland Keybinding Patterns

Hyprvoice is triggered via Hyprland keybindings. The bind type you choose affects reliability and workflow.

Simple toggle

# ~/.config/hypr/hyprland.conf
bind = SUPER, R, exec, hyprvoice toggle

Each press toggles between recording and idle. If you run into issues with text injection (stuck keys, wrong characters), try bindr instead — it fires on key release so modifiers are guaranteed released before the command runs.

Push-to-talk (hold-to-record)

Pair bind (press) with bindr (release) on the same key for hold-to-record:

# ~/.config/hypr/hyprland.conf
bind  = SUPER, R, exec, hyprvoice toggle   # key down → start recording
bindr = SUPER, R, exec, hyprvoice toggle    # key up   → stop and transcribe

Hold the key while speaking, release when done. Both lines send toggle to the daemon — the first starts the pipeline, the second stops it. Because the stop fires on release, modifiers are clean for injection.

bind vs bindr

Keyword Fires on
bind Key press (down)
bindr Key release (up)

With bindr, modifier keys (SUPER, CTRL, etc.) are fully released before the command executes. This can prevent modifiers from interfering with text injection.

Unified Provider System

Hyprvoice uses a unified provider system where API keys are configured once and shared between transcription and LLM features:

# Configure API keys for providers you want to use
[providers.openai]
  api_key = "sk-..."           # Or set OPENAI_API_KEY env var

[providers.groq]
  api_key = "gsk_..."          # Or set GROQ_API_KEY env var

[providers.mistral]
  api_key = "..."              # Or set MISTRAL_API_KEY env var

[providers.elevenlabs]
  api_key = "..."              # Or set ELEVENLABS_API_KEY env var

[providers.deepgram]
  api_key = "..."              # Or set DEEPGRAM_API_KEY env var

API key resolution order:

  1. [providers.X] section in config
  2. Environment variable (OPENAI_API_KEY, GROQ_API_KEY, etc.)

Transcription Providers

Hyprvoice supports multiple transcription backends. See docs/providers.md for detailed comparisons.

Cloud Providers

OpenAI Whisper API

Cloud-based transcription using OpenAI's Whisper API:

[transcription]
provider = "openai"
model = "whisper-1"
language = ""                   # Empty for auto-detect, or "en", "es", "fr", etc.

Features:

  • High-quality transcription
  • Supports 50+ languages
  • Auto-detection or specify language for better accuracy

Groq Whisper API (Transcription)

Fast cloud-based transcription using Groq's Whisper API:

[transcription]
provider = "groq-transcription"
model = "whisper-large-v3"      # Or "whisper-large-v3-turbo" for faster processing
language = ""                   # Empty for auto-detect, or "en", "es", "fr", etc.

Features:

  • Ultra-fast transcription (significantly faster than OpenAI)
  • Same Whisper model quality
  • Supports 50+ languages
  • Free tier available with generous limits

Mistral Voxtral

Transcription using Mistral's Voxtral API, excellent for European languages:

Note: Mistral's API supports streaming responses, but it is not real-time audio streaming. Hyprvoice treats Voxtral as batch-only.

[transcription]
provider = "mistral-transcription"
model = "voxtral-mini-latest"
language = ""                   # Empty for auto-detect

ElevenLabs Scribe

Transcription using ElevenLabs' Scribe API with 57+ language support:

[transcription]
provider = "elevenlabs"
model = "scribe_v1"             # Or "scribe_v2" for lower latency (batch)
language = ""                   # Empty for auto-detect

Features:

  • 57+ languages supported
  • Both batch and streaming models available
  • Ultra-low latency streaming options

Deepgram Nova

Fast streaming transcription using Deepgram's Nova models:

[providers.deepgram]
  api_key = "..."               # Or set DEEPGRAM_API_KEY env var

[transcription]
provider = "deepgram"
model = "nova-3"                # Or "nova-2" for different language support
language = ""                   # Empty for auto-detect

Features:

  • Flux: streaming-only, English with turn detection
  • Nova-3: 42 languages, best accuracy (batch+streaming)
  • Nova-2: 33 languages, faster with filler word detection (batch+streaming)
  • Excellent for real-time transcription and live captions

Local Transcription (whisper-cpp)

Run Whisper models locally on your machine. No API keys, no network latency, complete privacy.

Prerequisites:

  1. Install whisper-cli: https://github.com/ggerganov/whisper.cpp
  2. Download a model: hyprvoice model download base.en
[transcription]
provider = "whisper-cpp"
model = "base.en"               # English-only model (fastest)
language = ""                   # Empty for auto-detect (use "en" for English-only models)
threads = 0                     # 0 = auto (uses NumCPU - 1)

Available models:

Model Size Languages Best For
tiny.en 75MB English only Quick tests, low-power devices
base.en 142MB English only Daily use, good balance
small.en 466MB English only Better accuracy
medium.en 1.5GB English only Best English accuracy
tiny 75MB 57 languages Quick multilingual
base 142MB 57 languages Daily multilingual use
small 466MB 57 languages Better multilingual
medium 1.5GB 57 languages Great accuracy
large-v1 2.9GB 57 languages Best accuracy
large-v2 2.9GB 57 languages Best accuracy
large-v3 3GB 57 languages Best accuracy
large-v3-turbo 1.6GB 57 languages Faster large-v3

Threads configuration:

  • threads = 0 (default): auto-detects, uses NumCPU - 1 to leave one core free
  • threads = 4: explicitly use 4 threads
  • Higher thread count = faster transcription but more CPU usage

Streaming Transcription

For real-time transcription, use streaming models:

# ElevenLabs streaming (realtime only)
[transcription]
provider = "elevenlabs"
model = "scribe_v2_realtime"
streaming = true

# Deepgram streaming (all models support streaming)
[transcription]
provider = "deepgram"
model = "nova-3"

# OpenAI Realtime
[transcription]
provider = "openai"
model = "gpt-4o-realtime-preview"

Streaming models:

Provider Model Latency Languages
ElevenLabs scribe_v2_realtime <150ms 57+
Deepgram flux-general-en Very Low en
Deepgram nova-3 Low 42
Deepgram nova-2 Very Low 33
OpenAI gpt-4o-realtime-preview Low 57

Language Configuration

Language is configured per transcription model in the [transcription] section:

[transcription]
provider = "openai"
model = "whisper-1"
language = ""                   # Empty for auto-detect (recommended)
# language = "en"               # English
# language = "es"               # Spanish
# language = "fr"               # French

When using hyprvoice configure, you select the language after choosing the model. Only languages supported by the selected model are shown.

Recommendations:

  • Use auto-detect (language = "") for most cases - it works well
  • Specify a language if you always speak the same language (slight accuracy boost)
  • English-only models (e.g., base.en) only support language = "en" or auto-detect

Supported Languages

Hyprvoice supports 57 languages:

Afrikaans (af), Arabic (ar), Armenian (hy), Azerbaijani (az), Belarusian (be), Bosnian (bs), Bulgarian (bg), Catalan (ca), Chinese (zh), Croatian (hr), Czech (cs), Danish (da), Dutch (nl), English (en), Estonian (et), Finnish (fi), French (fr), Galician (gl), German (de), Greek (el), Hebrew (he), Hindi (hi), Hungarian (hu), Icelandic (is), Indonesian (id), Italian (it), Japanese (ja), Kannada (kn), Kazakh (kk), Korean (ko), Latvian (lv), Lithuanian (lt), Macedonian (mk), Malay (ms), Marathi (mr), Maori (mi), Nepali (ne), Norwegian (no), Persian (fa), Polish (pl), Portuguese (pt), Romanian (ro), Russian (ru), Serbian (sr), Slovak (sk), Slovenian (sl), Spanish (es), Swahili (sw), Swedish (sv), Tagalog (tl), Tamil (ta), Thai (th), Turkish (tr), Ukrainian (uk), Urdu (ur), Vietnamese (vi), Welsh (cy)

Language-Model Compatibility

Some models only support English. When configuring via hyprvoice configure, only supported languages are shown for selection.

English-only models:

Provider Model
whisper-cpp tiny.en, base.en, small.en, medium.en

Deepgram models support fewer languages than the full 57 - see providers.md.

Validation behavior:

  1. At config time (TUI): Only languages supported by the selected model are shown
  2. At runtime: If config was manually edited to an invalid combination, hyprvoice logs a warning, sends a desktop notification, and falls back to auto-detect
# This combination will be rejected at validation:
[transcription]
provider = "whisper-cpp"
model = "base.en"                 # English only!
language = "es"                         # Error: model does not support Spanish

Model Management

Manage local whisper models with CLI commands:

List Models

# List all models
hyprvoice model list

# Filter by provider
hyprvoice model list --provider whisper-cpp

# Filter by type
hyprvoice model list --type transcription

Shows installed status [x] for local models and model details.

Download Models

# Download a whisper model
hyprvoice model download base.en

# Download with progress
hyprvoice model download large-v3

Cloud models (OpenAI, Groq, etc.) don't require download - this is for local models only.

Remove Models

# Remove a downloaded model
hyprvoice model remove base.en

LLM Post-Processing

LLM post-processing is enabled by default and significantly improves transcription quality. After transcription, the text is processed by an LLM to:

  • Remove stutters and repeated words ("I I I want" → "I want")
  • Add proper punctuation
  • Fix grammar errors
  • Remove filler words ("um", "uh", "like", "you know", etc.)

Basic Configuration

[llm]
  enabled = true               # Disable with false if you want raw transcriptions
  provider = "openai"          # "openai" or "groq"
  model = "gpt-4o-mini"        # OpenAI: "gpt-4o-mini", Groq: "llama-3.3-70b-versatile"

Post-Processing Options

All options are enabled by default. Disable specific ones as needed:

[llm.post_processing]
  remove_stutters = true       # "I I I want" → "I want"
  add_punctuation = true       # Adds periods, commas, etc.
  fix_grammar = true           # Fixes grammatical errors
  remove_filler_words = true   # Removes "um", "uh", "like", "you know"

Custom Prompts

Add custom instructions for specific use cases:

[llm.custom_prompt]
  enabled = true
  prompt = "Format as bullet points"

Use cases for custom prompts:

  • "Format as bullet points" - for note-taking
  • "Keep technical terms exactly as spoken" - for programming dictation
  • "Use formal language" - for professional documents
  • "Translate to Spanish" - for translation workflows

LLM Provider Recommendations

Provider Model Best For
OpenAI gpt-4o-mini Best quality/cost balance (default)
Groq llama-3.3-70b-versatile Fastest processing, free tier

Keywords

Keywords help both transcription and LLM understand domain-specific terms, names, and technical vocabulary:

keywords = ["Hyprland", "Wayland", "PipeWire", "Claude", "TypeScript"]

How keywords work:

  • Transcription: Passed as provider-specific hints (prompt/keyterms/keywords) when supported to improve recognition
  • LLM: Included in the system prompt to ensure correct spelling

When to use keywords:

  • Names of people, companies, or products
  • Technical terminology specific to your field
  • Acronyms or abbreviations
  • Words commonly misheard by speech-to-text

Recording Configuration

Audio capture settings:

[recording]
sample_rate = 16000        # Audio sample rate in Hz (16000 recommended for speech)
channels = 1               # Number of audio channels (1 = mono, 2 = stereo)
format = "s16"             # Audio format (s16 = 16-bit signed integers)
buffer_size = 8192         # Internal buffer size in bytes (larger = less CPU, more latency)
device = ""                # PipeWire device name (empty = default microphone)
channel_buffer_size = 30   # Audio frame buffer size (frames to buffer)
timeout = "5m"             # Maximum recording duration (e.g., "30s", "2m", "5m")

Recording Timeout

  • Prevents accidental long recordings that could consume resources
  • Default: 5 minutes ("5m")
  • Format: Go duration strings like "30s", "2m", "10m"
  • Recording automatically stops when timeout is reached

Text Injection

Configurable text injection with multiple backends:

[injection]
backends = ["ydotool", "wtype", "clipboard"]  # Ordered fallback chain
ydotool_timeout = "5s"
wtype_timeout = "5s"
clipboard_timeout = "3s"

Injection Backends

  • ydotool: Uses ydotool (requires ydotoold daemon for ydotool v1.0.0+). Most compatible with Chromium/Electron apps.
  • wtype: Uses wtype for Wayland. May have issues with some Chromium-based apps (known upstream bug).
  • clipboard: Copies text to clipboard only. Most reliable, but requires manual paste.

Fallback Chain

Backends are tried in order. The first successful one wins. Example configurations:

# Clipboard only (safest, always works)
backends = ["clipboard"]

# wtype with clipboard fallback
backends = ["wtype", "clipboard"]

# Full fallback chain (default) - best compatibility
backends = ["ydotool", "wtype", "clipboard"]

# ydotool only (if you have it set up)
backends = ["ydotool"]

ydotool Setup

ydotool requires the ydotoold daemon running (for ydotool v1.0.0+) and access to /dev/uinput:

# Start ydotool daemon (systemd)
systemctl --user enable --now ydotool

# Or add user to input group
sudo usermod -aG input $USER
# Then logout/login

# For Hyprland, add to config to set correct keyboard layout:
# device:ydotoold-virtual-device {
#     kb_layout = us
# }

Notifications

Desktop notification settings:

[notifications]
enabled = true             # Enable/disable notifications
type = "desktop"           # "desktop", "log", or "none"

Notification Types

  • desktop: Use notify-send for desktop notifications
  • log: Log messages to console only
  • none: Disable all notifications

Custom Notification Messages

You can customize notification text via the [notifications.messages] section:

[notifications.messages]
  [notifications.messages.recording_started]
    title = "Hyprvoice"
    body = "Recording Started"
  [notifications.messages.transcribing]
    title = "Hyprvoice"
    body = "Recording Ended... Transcribing"
  [notifications.messages.llm_processing]
    title = "Hyprvoice"
    body = "Processing..."
  [notifications.messages.config_reloaded]
    title = "Hyprvoice"
    body = "Config Reloaded"
  [notifications.messages.operation_cancelled]
    title = "Hyprvoice"
    body = "Operation Cancelled"
  [notifications.messages.recording_aborted]
    body = "Recording Aborted"
  [notifications.messages.injection_aborted]
    body = "Injection Aborted"

Emoji-only example (for minimal pill-style notifications):

[notifications.messages.recording_started]
  title = ""
  body = "🎙️"

Example Configurations

Fast Transcription Only (No LLM)

[providers.groq]
  api_key = "gsk_..."

[transcription]
  provider = "groq-transcription"
  model = "whisper-large-v3-turbo"
  language = ""                 # Auto-detect

[llm]
  enabled = false

High Quality with OpenAI (Default)

[providers.openai]
  api_key = "sk-..."

[transcription]
  provider = "openai"
  model = "whisper-1"
  language = ""                 # Auto-detect

[llm]
  enabled = true
  provider = "openai"
  model = "gpt-4o-mini"

Budget-Friendly with Groq

[providers.groq]
  api_key = "gsk_..."

[transcription]
  provider = "groq-transcription"
  model = "whisper-large-v3-turbo"
  language = ""                 # Auto-detect

[llm]
  enabled = true
  provider = "groq"
  model = "llama-3.3-70b-versatile"

Mixed Providers (Groq Transcription + OpenAI LLM)

[providers.openai]
  api_key = "sk-..."

[providers.groq]
  api_key = "gsk_..."

[transcription]
  provider = "groq-transcription"
  model = "whisper-large-v3-turbo"
  language = ""                 # Auto-detect

[llm]
  enabled = true
  provider = "openai"
  model = "gpt-4o-mini"

Local Transcription (Privacy-First)

# No API keys needed!

[transcription]
  provider = "whisper-cpp"
  model = "base.en"
  language = ""                 # Auto-detect
  threads = 0                   # Auto-detect (NumCPU - 1)

[llm]
  enabled = false               # No LLM for full privacy

Real-Time Streaming with Deepgram

[providers.deepgram]
  api_key = "..."

[transcription]
  provider = "deepgram"
  model = "nova-3"              # All Deepgram models are streaming
  language = ""                 # Auto-detect

[llm]
  enabled = false               # Streaming doesn't need LLM post-processing

Ultra-Low Latency Streaming

[providers.elevenlabs]
  api_key = "..."

[transcription]
provider = "elevenlabs"
model = "scribe_v2_realtime"   # <150ms latency
streaming = true
  language = ""                 # Auto-detect

[llm]
  enabled = false

Specific Language Setup

[providers.openai]
  api_key = "sk-..."

[transcription]
  provider = "openai"
  model = "whisper-1"
  language = "es"               # Always transcribe as Spanish

[llm]
  enabled = true
  provider = "openai"
  model = "gpt-4o-mini"

Legacy Configs

Older config formats are no longer supported. If your config uses any of these fields, rerun onboarding to regenerate a supported config:

  • transcription.api_key
  • injection.mode
  • general.language
  • transcription.provider = "groq-translation"

Run hyprvoice onboarding to generate a new config, then hyprvoice configure for advanced settings.

Configuration Hot-Reloading

The daemon automatically watches the config file for changes and applies them immediately:

  • Notification settings: Applied instantly
  • Injection settings: Applied to current and future operations
  • Recording/Transcription/LLM settings: Applied to new recording sessions
  • Invalid configs: Rejected with error notification, daemon continues with previous config