Skip to main content

Wayland hotkey dictation CLI and daemon; native ASR/LLM fetched on first run.

Project description

Dictum

Dictum is a Python voice-to-text command tool designed for Wayland compositors such as Hyprland and Sway. It is intended to be triggered from a hotkey, record microphone audio, transcribe it with Parakeet TDT v3 0.6B, polish the transcription with a local or cloud LLM, and send the final text to the active window, clipboard, stdout, or a file.

Goals

  • Fast hotkey workflow for dictation and text transformation.
  • Persistent daemon for state, warm models, and lower latency.
  • Companion CLI for key bindings and scripting.
  • Pluggable ASR, LLM, recorder, and output backends.
  • Wayland-first output through wtype, ydotool, wl-copy, or stdout.

Architecture

Hyprland/Sway hotkey
  -> dictum CLI (thin IPC client)
  -> daemon command over local Unix socket
  -> record mic audio (sounddevice/PipeWire)
  -> transcribe with Parakeet (CrispASR HTTP server, port 8081)
  -> polish with LLM (llama.cpp server, port 8080)
  -> paste/copy/print/save result

Moving Parts

Component Technology Purpose
CLI Python + Typer Hotkey-friendly commands (toggle, start, stop, once, status)
Daemon Python + asyncio State machine, IPC server, pipeline orchestration
Recorder sounddevice (PortAudio) PipeWire/PulseAudio capture, silence watchdog
ASR CrispASR (C++/Vulkan) Parakeet TDT v3 0.6B GGUF, HTTP server mode (warm)
LLM llama.cpp (C++/Vulkan) Qwen 3.5-4B GGUF, OpenAI-compatible HTTP server (warm)
Output wtype / ydotool / wl-copy Wayland text insertion
Notify D-Bus (gdbus) Desktop notifications

State Machine

idle -> recording -> transcribing -> polishing -> pasting -> idle
              \-> failed (on error) ----------------------------> idle

polishing is skipped if the profile disables LLM rewriting.


Quick Start

1. Prerequisites

  • GPU: Discrete GPU with Vulkan support (optional but recommended)
  • Vulkan loader: libvulkan1 / vulkan-loader + a compatible ICD
  • Python: 3.11+ with uv (recommended) or pip

2. Install Dictum

# From PyPI, once published
uv tool install dictum-asr

# Or from a local source checkout while developing
git clone https://github.com/hermitm0nk/dictum.git
cd dictum
uv tool install .

The wheel is pure Python and tiny (tens of KB). The native C++ binaries are no longer built from source at install time. Instead, Dictum downloads pinned upstream releases on first use:

  • llama.cppllama-server (Vulkan build, b9699)
  • CrispASRparakeet-main (Vulkan build, v0.7.2)

Pre-fetch them explicitly (recommended before binding a hotkey):

dictum native install            # fetch both, Vulkan variant
dictum native install --lib llama
dictum native install --variant cpu   # if no Vulkan ICD is present
dictum native status             # show what's installed and where

Binaries land under $DICTUM_NATIVE_DIR when set, otherwise under $XDG_DATA_HOME/dictum/native/, or ~/.local/share/dictum/native/. The llama-server binary ships with RUNPATH=$ORIGIN so it finds its sibling .so files automatically; parakeet-main is statically linked. No LD_LIBRARY_PATH is required in normal use.

To override the bundled binaries entirely, set DICTUM_LLM_BIN and/or DICTUM_PARAKEET_BIN to point at your own builds — Dictum will not attempt to download when an override is set.

3. Download Models

# Parakeet ASR (multilingual, 4-bit quant)
huggingface-cli download cstr/parakeet-tdt-0.6b-v3-GGUF \
  parakeet-tdt-0.6b-v3-q4_k.gguf \
  --local-dir ~/.cache/dictum/models/

# Qwen LLM (Q3 quant for polishing)
huggingface-cli download unsloth/Qwen3.5-4B-GGUF \
  Qwen3.5-4B-Q3_K_M.gguf \
  --local-dir ~/.cache/dictum/models/

By default Dictum downloads models on first use into $DICTUM_MODEL_DIR when set, otherwise into $XDG_CACHE_HOME/dictum/models or ~/.cache/dictum/models.

4. Configure (Optional)

mkdir -p ~/.config/dictum
cp examples/config.toml ~/.config/dictum/config.toml
# Edit profiles, ASR/LLM settings, output target

Usage

Start the Daemon

# Foreground (testing)
dictum daemon --profile default

# Or as systemd user service (persistent, see below)

Hotkey Commands

# Toggle recording (press once to start, again to stop & process)
dictum toggle --profile default --result paste

# Explicit start/stop
dictum start --profile default
dictum stop --result paste

# One-shot (no daemon needed)
dictum once --result stdout --duration 30

# Status
dictum status
dictum status --json

Output Targets (--result)

Target Behavior
paste Types into focused window via wtype/ydotool (fallback: clipboard)
clipboard Copies to clipboard via wl-copy
stdout Prints to terminal
file Writes to /tmp/dictum-output.txt
none No output

Systemd User Service (Persistent Daemon)

# Install, enable (starts at login), but do not start now
dictum service install

# Install and start immediately
dictum service install --now

# Check status
dictum service status

# Remove the service
dictum service uninstall

The unit file is bundled with the wheel and copied to ~/.config/systemd/user/dictum.service (or $XDG_CONFIG_HOME/systemd/user/). User units start at graphical/login session, not at boot.

The bundled unit (dictum/data/dictum.service):

[Unit]
Description=Dictum voice dictation daemon
After=graphical-session.target pipewire.service

[Service]
Type=simple
ExecStart=%h/.local/bin/dictum daemon
Restart=on-failure
RestartSec=2

[Install]
WantedBy=default.target

You can still manage the service directly with systemctl --user {start,stop,restart,status} dictum. Edit the installed unit file to customize ExecStart (e.g. add --profile flags) and run systemctl --user daemon-reload.


Hyprland Binding

Add to ~/.config/hypr/hyprland.conf:

# Dictum voice dictation (ScrollLock to toggle)
bind = , Scroll_Lock, exec, dictum toggle --profile default --result paste

Reload config:

hyprctl reload

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dictum_asr-0.2.0.tar.gz (43.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dictum_asr-0.2.0-py3-none-any.whl (38.5 kB view details)

Uploaded Python 3

File details

Details for the file dictum_asr-0.2.0.tar.gz.

File metadata

  • Download URL: dictum_asr-0.2.0.tar.gz
  • Upload date:
  • Size: 43.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dictum_asr-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d08687bb58f73addd875da1e24473095a90f3f98c2baedc3968b54215b0162c5
MD5 db0d0373a25752deab6b29517a7ba6a3
BLAKE2b-256 b5fc98ec8a017f8c4e7b2d605005c7c24885eec0a9dcc760d36f5286c09081e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for dictum_asr-0.2.0.tar.gz:

Publisher: pypi-publish.yaml on hermitm0nk/dictum

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dictum_asr-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: dictum_asr-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 38.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dictum_asr-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eb723010947d771a3dfeb286c8038bd5c711eff7ce9cdfd764ec64a04e5cc988
MD5 935973916f5d9d8d6c7e6dbed096547f
BLAKE2b-256 6042a8f8ea340e941c4d2566b235c3aa05192df332f39d634fa6188182fd7758

See more details on using hashes here.

Provenance

The following attestation bundles were made for dictum_asr-0.2.0-py3-none-any.whl:

Publisher: pypi-publish.yaml on hermitm0nk/dictum

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page