talk-rs 0.7.1

Voice dictation for Linux -- record, transcribe, and paste
# talk-rs Configuration File
#
# This file contains all required settings for talk-rs operation.
# Replace all <PLACEHOLDER> values with your actual configuration.
#
# For more information, see: https://github.com/talk-rs/talk-rs

# Required: Output directory for recordings, screenshots, and clipboard saves.
# The `record` command saves recordings here by default (memo-YYYY-MM-DD-HH-MM-SS.ogg).
# Must be an absolute path that is writable.  A leading `~` (or `~/`)
# is expanded to your home directory.
output_dir: <PLACEHOLDER>

# Optional: Recording quality for the `record` command's .ogg output.
#
# These settings control the quality of recordings meant for a HUMAN
# to listen to / share.  They are independent of transcription: audio
# sent to the transcription providers is always downsampled to 16 kHz
# mono internally (both Voxtral and Whisper operate at 16 kHz), so
# these knobs do NOT affect transcription accuracy or upload size.
#
# Defaults (used when this section is omitted): 48 kHz, mono, 128 kbps.
# Also overridable via TALK_RS_RECORDING_SAMPLE_RATE /
# TALK_RS_RECORDING_CHANNELS / TALK_RS_RECORDING_BITRATE env vars.
# recording:
#   sample_rate: 48000   # Hz (48000 = full-band, no resampling)
#   channels: 1          # 1 = mono (recommended for voice), 2 = stereo
#   bitrate: 128000      # bps (Opus; 128 kbps is transparent for voice)

# Required: Transcription Providers Configuration
# Configure at least one provider (Mistral or OpenAI)
providers:
  # Mistral API Configuration
  mistral:
    # Your Mistral API key for authentication
    # Get this from: https://console.mistral.ai/
    api_key: <PLACEHOLDER>

    # Base URL for the Mistral API (optional, defaults to "https://api.mistral.ai")
    # Override to point at a self-hosted or API-compatible endpoint.
    # Only the base URL — path segments are appended automatically.
    # url: https://api.mistral.ai

    # Model name for transcription (optional, defaults to "voxtral-mini-2507")
    # Available models: voxtral-mini-2507, voxtral-mini-2602, voxtral-mini-latest
    # V2 models (2602+) support speaker diarization via --diarize
    # model: voxtral-mini-2507

    # Context bias: comma-separated words/phrases to improve transcription accuracy
    # Up to 100 words. Useful for proper nouns, technical terms, domain vocabulary.
    # Optimized for English; experimental for other languages.
    # context_bias: "Kalysto,talk-rs,Voxtral,cpal,tokio"

    # Text-to-speech (used by the `speak` command with --provider mistral).
    # The API key above is SHARED between speech-to-text and text-to-speech;
    # there is no separate voxtral section.
    #
    # Model for the /v1/audio/speech endpoint (optional, defaults to
    # "voxtral-mini-tts-latest").
    # tts_model: voxtral-mini-tts-latest
    #
    # Default preset voice id (a Mistral voice UUID) used when --voice is not
    # given.  List available voices with GET /v1/audio/voices?voice_type=preset.
    # tts_voice: "5a271406-039d-46fe-835b-fbbb00eaf08d"   # Marie (fr_FR)

  # OpenAI API Configuration (optional)
  # openai:
  #   api_key: <PLACEHOLDER>
  #   url: https://api.openai.com               # base URL (optional, for compatible endpoints)
  #   model: gpt-transcribe                     # batch default
  #   realtime_model: gpt-live-transcribe       # realtime WebSocket default
  #
  #   # Optional migration hints. Omit any field you do not need.
  #   prompt: "Preserve punctuation and spell product names exactly."
  #   keywords: [Kalysto, talk-rs]               # gpt-transcribe / gpt-live-transcribe
  #   languages: [fr, en]                        # expected languages, ordered by preference
  #   realtime_delay: low                        # minimal | low | medium | high | xhigh
  #
  # New defaults and legacy capabilities:
  # - gpt-transcribe (batch) sends prompt, repeated keywords[], repeated
  #   languages[], and response_format=json.
  # - gpt-live-transcribe (realtime) sends prompt, keywords, languages, and
  #   delay under session.audio.input.transcription.
  # - whisper-1 remains available for segment/word timestamps, subtitles,
  #   and translation workflows. It accepts prompt and one singular language,
  #   uses response_format=verbose_json, but not keywords or multiple languages.
  # - gpt-4o-transcribe and gpt-4o-mini-transcribe remain batch choices.
  # - gpt-realtime-whisper remains a realtime choice; it accepts prompt and one
  #   singular language, but not keywords, multiple languages, or realtime_delay.
  # Incompatible configured hints fail locally before HTTP/WebSocket traffic;
  # they are never silently dropped. There is no structured previous-turn field:
  # earlier-turn context is managed by the OpenAI service where supported.
  #
  # Environment overrides use the same field names:
  # TALK_RS_PROVIDERS_OPENAI_PROMPT, TALK_RS_PROVIDERS_OPENAI_KEYWORDS,
  # TALK_RS_PROVIDERS_OPENAI_LANGUAGES, TALK_RS_PROVIDERS_OPENAI_REALTIME_DELAY.
  # KEYWORDS and LANGUAGES are comma-separated; whitespace is trimmed and empty
  # entries are ignored (for example: "Kalysto, talk-rs" and "fr, en").
  #
  # Direct-OpenAI prices checked 2026-07-31:
  # gpt-transcribe $0.0045/min ($0.27/hr); whisper-1 $0.006/min ($0.36/hr).
  # gpt-transcribe is 25% lower, saving $0.09 per hour.

  # Parakeet local backend (on-device, offline, CPU). No API key.
  # NVIDIA Parakeet TDT 0.6b v3, 25 European languages incl. French.
  # The model (~640 MB INT8) auto-downloads on first use into
  # ~/.local/share/talk-rs/models/parakeet-tdt-0.6b-v3-int8/ and is
  # cached forever after (fully offline thereafter).
  # Requires the `parakeet` build feature (enabled by default; drop
  # via `cargo build --release --no-default-features`).
  # parakeet:
  #   variant: int8          # int8 (default, ~640 MB) — fp32 not yet available as a prebuilt download
  #   # model_dir: ~/.local/share/talk-rs/models/parakeet-tdt-0.6b-v3-int8   # override cache location
  #   num_threads: 2         # decode threads (default 2)
  #   # model: parakeet-tdt-0.6b-v3-int8   # logical name surfaced in cache keys / metadata

  # Kokoro local TTS backend (on-device, offline, CPU). No API key.
  # Multi-language text-to-speech used by the `speak` command with
  # --provider kokoro.  The model (~350 MB) auto-downloads on first use
  # into ~/.local/share/talk-rs/models/kokoro-multi-lang-v1_0/ and is
  # cached forever after (fully offline thereafter).
  # Requires the `kokoro` build feature (enabled by default; drop via
  # `cargo build --release --no-default-features`).
  #
  # Language handling is config-driven and agnostic: the requested
  # language (--lang / lang below) selects the phonemizer.  The stock
  # model ships one baked language (en-us); other languages are derived
  # on demand by patching the model's ONNX voice metadata, cached as
  # model-<lang>.onnx next to the stock model.
  # kokoro:
  #   # model_dir: ~/.local/share/talk-rs/models/kokoro-multi-lang-v1_0   # override cache location
  #   voice: af_heart        # default voice name (af_heart, am_michael, ff_siwis, …)
  #   num_threads: 4         # inference threads (default 4)
  #   lang: en               # default phonemization language (en, fr, …)

# Optional: Default provider when --provider is not specified.
# Valid values: mistral, openai, parakeet.
# transcription:
#   default_provider: mistral

# Optional: Default text-to-speech provider for the `speak` command,
# used when --provider is not specified.  Valid values: kokoro, mistral.
# When omitted, `speak` prefers the local Kokoro backend if a
# providers.kokoro section exists, else falls back to Mistral.
# speak:
#   default_provider: kokoro

# Optional: Visual and Audio Indicators
# Configure feedback mechanisms during recording
indicators:
  # Interval between boop sounds in milliseconds
  # Set to 0 to disable audio feedback
  boop_interval_ms: 5000

  # Show visual indicator overlay during recording
  # Set to false to disable visual feedback
  visual_overlay: true

  # In-badge audio visualizer during recording (disabled by default).
  # Available modes: waterfall, amplitude, spectrum
  # Also settable via --viz <MODE> or TALK_RS_INDICATORS_VIZ env var.
  # viz: waterfall

  # Monochrome visualizer (theme-aware: white on dark, black on light).
  # Also settable via --mono or TALK_RS_INDICATORS_MONO env var.
  # mono: false

# Optional: Paste Behaviour
# Configure how transcribed text is pasted into the target application.
#
# Omitting `paste:` entirely reproduces the default: chunk text at 150
# characters, then paste each chunk via Ctrl+Shift+V (clipboard).
#
# Two schemas are accepted:
#
# ── SCHEMA 1: LEGACY FLAT (still fully supported) ────────────────────────────
#
# paste:
#   # Maximum characters per clipboard paste chunk (default: 150).
#   # Text longer than this is split on word boundaries into consecutive
#   # paste keystrokes.  Keeping chunks small avoids terminal paste-summary
#   # collapse.  Set to 0 to disable chunking.  Also --no-chunk-paste.
#   chunk_chars: 150
#
#   # Paste shortcut sent after loading the clipboard (default: ctrl_shift_v).
#   # Use ctrl_v for terminals that don't support Ctrl+Shift+V.
#   shortcut: ctrl_shift_v   # or: ctrl_v
#
#   # Milliseconds to wait for the TARGET WINDOW to actually fetch each
#   # clipboard chunk before retrying or aborting (default: 500).
#   # This is a per-attempt deadline: if the target doesn't fetch within
#   # this window, talk-rs re-focuses the target window and re-sends the
#   # paste keystroke (up to target_fetch_retries additional attempts).
#   # After all retries are exhausted the paste aborts with a red overlay
#   # and alert sound, and your original clipboard is restored.
#   # Total effective wait before abort = chunk_fetch_timeout_ms × (1 + target_fetch_retries).
#   # The wait short-circuits as soon as the fetch lands, so a higher
#   # value costs nothing in the common case.
#   chunk_fetch_timeout_ms: 500
#
#   # Number of automatic retries when the target app doesn't fetch a
#   # chunk within chunk_fetch_timeout_ms (default: 2).  On each retry,
#   # talk-rs re-focuses the target window and re-sends the paste
#   # keystroke.  After all retries are exhausted the paste aborts with
#   # a red overlay + alert sound, and your original clipboard is restored.
#   target_fetch_retries: 2
#
#   # Quiet-window in ms used to learn how many times the target fetches
#   # each chunk (default: 50).  After the first fetch, talk-rs waits
#   # this long for additional fetches before declaring the count stable.
#   # Subsequent chunks must reach the same count before advancing.
#   target_quiescence_ms: 50
#
#   # DEPRECATED / no-op.  Accepted for backward compatibility but has
#   # no effect.  The old settle-loop heuristic was replaced by
#   # target-confirmation (see chunk_fetch_timeout_ms above).
#   # restore_settle_ms: 200
#
# ── SCHEMA 2: NEW TREE (composable node tree) ────────────────────────────────
#
# The tree schema lets you route paste behaviour per display server and
# per target application.  Each node has a `node:` key that selects its
# type.  Nodes are composable: most accept a `child:` (or `children:`)
# that is itself a node.
#
# Available node types:
#   detect-display-server  -- routes by $WAYLAND_DISPLAY (x11 / wayland branch)
#   match-wm-class         -- first-match routing on "<instance>.<class>" glob
#   chunk                  -- splits text into word-boundary chunks, delegates each
#   clipboard              -- sets clipboard + sends paste shortcut, waits for target fetch
#   xtest-type             -- types text via XTest synthetic keystrokes (no clipboard;
#                             ASCII/Latin-1 only; non-Latin-1 chars skipped with a warning)
#
# Full example (uncomment and adjust to taste):
#
# paste:
#   node: detect-display-server
#   x11:
#     node: match-wm-class
#     patterns:
#       # Terminals: type directly via XTest (no clipboard needed)
#       - match: "*.Alacritty"
#         child:
#           node: xtest-type
#       # Terminals using Ctrl+Shift+V (most VTE-based terminals)
#       - match: "*.gnome-terminal-server"
#         child:
#           node: clipboard
#           shortcut: ctrl_shift_v
#           chunk_fetch_timeout_ms: 500
#           target_fetch_retries: 2
#           target_quiescence_ms: 50
#       # Emacs: uses Ctrl+Y (yank); no chunking needed
#       - match: "emacs.*"
#         child:
#           node: clipboard
#           shortcut: ctrl_v
#           chunk_fetch_timeout_ms: 500
#           target_fetch_retries: 2
#           target_quiescence_ms: 50
#       # Firefox and most GUI apps: chunk then paste via Ctrl+Shift+V
#       - match: "*.firefox"
#         child:
#           node: chunk
#           chunk_chars: 150
#           child:
#             node: clipboard
#             shortcut: ctrl_shift_v
#             chunk_fetch_timeout_ms: 500
#             target_fetch_retries: 2
#             target_quiescence_ms: 50
#     # Default for any window not matched above
#     default:
#       node: chunk
#       chunk_chars: 150
#       child:
#         node: clipboard
#         shortcut: ctrl_shift_v
#         chunk_fetch_timeout_ms: 500
#         target_fetch_retries: 2
#         target_quiescence_ms: 50
#   # wayland: currently errors ("Wayland paste not supported"); X11 only for now.

# Optional: Runtime Audio Settings
# audio:
#   # Auto-switch a connected Bluetooth headset to its Hands-Free
#   # Profile (HFP) for the duration of a recording so the headset
#   # microphone is enabled, then restore the original profile
#   # (typically A2DP) on stop.  Default: true.  Override per-invocation
#   # with --no-bt-auto-switch, or globally via the
#   # TALK_RS_AUDIO_BT_AUTO_SWITCH env var (true/false/yes/no/1/0/on/off).
#   bt_auto_switch: true