Skip to content

collectifweb/aparte

Repository files navigation

Aparté

👋 Looking for Murmur? You found it.

This project was called Murmur until it was renamed to Aparté, to avoid confusion with the unrelated Murmure project. Same repository, same app, new name.

Already running Murmur? Nothing breaks: your config is migrated automatically, MURMUR_* environment variables still work, and the old murmur command still launches Aparté — so a global shortcut bound to it keeps working. See Upgrading from Murmur.

CI License: MIT

Aparté is a local-first dictation app for Linux. It can run as a CLI, as a command bound to a global keyboard shortcut, or as a lightweight local desktop web app.

Nothing leaves your machine: Whisper runs locally, formatting runs locally, and there is no account, no API key, and no network call. It is also the only dictation app that takes French typography seriously — non-breaking spaces before ? ! ; :, real « » quotes, curly apostrophes.

The loop, in four steps:

  1. Capture speech or accept an audio file.
  2. Transcribe with a local Whisper backend.
  3. Polish the raw transcript with punctuation, capitalization, filler cleanup, lists, and optional local LLM formatting.
  4. Copy or paste the result into the active Linux desktop session.

Screenshots

Aparté dictation screen

One screen: a Talk button, a transcript editor, and nothing else in the way. The transcript is set in a serif face, so the French typography Aparté produces is actually visible — look at the « », the curly apostrophes, and the spacing before ; and ?.

Aparté while recording

Aparté follows your desktop's light or dark theme. While the microphone is open, the button is the only saturated thing on screen — you can tell it is recording from the corner of your eye, and without relying on colour alone (the icon and the label change too).

Grouped settings and built-in setup diagnostics — the diagnostics show what is installed and the exact command to fix anything missing, so any Linux user can get set up without the terminal. The interface is available in English and French.

Settings panel Setup and diagnostics panel

Current status

Aparté is in daily use: dictate with a global shortcut, and the text lands formatted in whichever app is focused. Text polishing and the desktop UI work out of the box; audio transcription activates when one of these local backends is available:

  • faster-whisper Python package (recommended — the only one that supports the My words vocabulary setting)
  • openai-whisper Python package
  • whisper.cpp CLI via APARTE_WHISPER_CPP

For best formatting quality, run Ollama locally and set APARTE_POLISH_BACKEND=ollama. For consistent spelling of names, products, and acronyms, use My words and Corrections in Settings — see Teaching Aparté your vocabulary.

Still to come: a floating window so the live preview is visible when you dictate with the global shortcut rather than only inside the app, and capturing a correction straight from the editor instead of retyping it in Settings.

Install

Two ways to install. The script is the easy path; the manual venv install gives you more control.

Option A — guided script (recommended)

git clone https://github.com/collectifweb/aparte.git
cd aparte
./scripts/install-linux.sh                       # Whisper + recording + default config + desktop launcher (icon/menu)
./scripts/install-linux.sh --with-system-deps    # also apt-installs the recording/clipboard/paste tools

The script auto-adds GPU support (the cuda extra) when it detects an NVIDIA GPU, and registers the desktop icon/menu entry for you.

Option B — manual venv install

git clone https://github.com/collectifweb/aparte.git
cd aparte
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[whisper,recording]"  # add ,cuda for NVIDIA GPUs — see "GPU acceleration" below

This [whisper,recording] baseline is what makes Aparté an actual dictation app: whisper enables transcription and recording enables microphone capture. A bare pip install -e . only gives you text polishing and the desktop UI — it cannot transcribe or record.

Then verify the setup and install the desktop launcher (the manual path does not add the icon/menu entry by itself — only install-linux.sh does):

aparte doctor            # green/red status for every dependency, with the fix command for each gap
aparte install-desktop   # add the app icon + menu entry (use --print to preview the entry first)

Updating an existing install

Open the desktop app, click Setup, and use the Update section at the bottom: it checks the remote when you press Check, shows what is waiting, pulls it, reinstalls, and restarts Aparté. It refuses — and says why — when the folder has uncommitted changes, when the branch tracks no remote, or when Aparté wasn't installed from a clone.

To do it by hand instead, pull the latest code in the folder you already cloned and re-run the script — don't clone a second copy:

cd aparte          # the directory you installed into
git pull
./scripts/install-linux.sh

Re-running is safe: the existing .venv is reused, dependencies are upgraded in place, and config init is a no-op. Cloning Aparté again into a new folder instead leaves you with two separate installs (each with its own multi-GB .venv) and a desktop launcher and autostart entry that can point at different copies.

On a manual venv install (Option B), update with:

cd aparte
git pull
source .venv/bin/activate
python -m pip install -e ".[whisper,recording]"   # add ,cuda for NVIDIA GPUs

If git pull reports "no tracking information for the current branch", you're on a local branch that was never pushed. Switch to main first (git checkout main), then pull.

Upgrading from Murmur (the previous name)

Pull and re-run the install script as above; the rename is handled for you:

  • ~/.config/murmur/config.json is moved to ~/.config/aparte/config.json on first run, so your settings, replacements, and snippets carry over.
  • MURMUR_* environment variables are still read as a fallback, so existing shell profiles and scripts keep working.
  • The old murmur command still runs Aparté, so a global shortcut bound to the old binary keeps working. It is deprecated and will be removed later — re-run aparte install-hotkey to repoint the shortcut at the new command.
  • The old desktop launcher, icon, and autostart entry are removed when you re-run aparte install-desktop / aparte install-autostart, so you don't end up with two menu entries or two servers competing at login.

Extras, à la carte

Extra Adds
whisper faster-whisper transcription backend (required for dictation)
recording microphone capture via sounddevice (required for live dictation)
cuda NVIDIA GPU acceleration — see GPU acceleration below

System packages

sudo apt install alsa-utils ffmpeg wl-clipboard wtype xclip xdotool

Use Wayland tools (wl-copy, wtype) on Wayland, or X11 tools (xclip, xdotool) on X11.

GPU acceleration (NVIDIA, optional)

python -m pip install -e ".[whisper,recording,cuda]"

This installs the CUDA runtime libraries as pip wheels inside the venv — no system CUDA toolkit and no driver changes, so it will not touch the GPU drivers your games or other apps rely on. The app preloads the libraries automatically, so GPU transcription works without setting LD_LIBRARY_PATH, and falls back to CPU automatically when CUDA is unusable.

Confirm the GPU is actually used (not merely installed):

.venv/bin/python -c "import ctranslate2; print(ctranslate2.get_cuda_device_count())"

> 0 means the GPU will be used; 0 means CPU fallback. Note that aparte doctor's "GPU acceleration (CUDA): ok" only confirms the CUDA libraries are importable — not that a device is reachable at runtime. Use the command above, or watch nvidia-smi during a dictation, to be sure. On older cards (Pascal / GTX 10-series), set APARTE_COMPUTE_TYPE=int8: the auto default picks float16, which is slow on those GPUs.

CLI examples

Polish raw text:

echo "hey sarah thanks for sending this euh i will review it tomorrow" | aparte polish

Transcribe an audio file and polish it:

aparte transcribe meeting.wav --polish

Record from the microphone, transcribe, polish, and copy:

aparte record --seconds 15 --polish --copy

Dictate directly into the active app:

aparte dictate --seconds 8

Use fixed-duration dictation as a global keyboard shortcut command in GNOME/KDE/XFCE:

aparte dictate --seconds 8 --target paste

For a more Flow-like shortcut, bind the same toggle command to one global hotkey. The first press starts recording; the second press stops, transcribes, polishes, and inserts:

aparte toggle --target paste

Check whether a toggle recording is already active:

aparte toggle --status

If direct paste is unavailable on your desktop, copy instead:

aparte toggle --target copy

Launch the Linux desktop app:

aparte desktop

Install a desktop launcher in ~/.local/share/applications:

aparte install-desktop

Run the desktop server automatically at login (writes ~/.config/autostart). It starts in the background without opening a browser, so the editor and the Settings tab are always available at http://127.0.0.1:8765:

aparte install-autostart
aparte install-autostart --remove   # undo

Global hotkey (recommended for dictating into other apps)

The Flow-like flow is one global shortcut bound to toggle: press once to start, press again to transcribe and insert into whatever app is focused (Slack, email, …). The binding is stored by your desktop and survives reboots, so no background process is required for it.

On Cinnamon and GNOME, Aparté can register the shortcut for you:

aparte install-hotkey                            # bind Super+Space to toggle dictation
aparte install-hotkey --key '<Control><Alt>d'    # pick another accelerator
aparte install-hotkey --print                    # show what it would bind, without applying
aparte install-hotkey --remove                   # remove it

It allocates a custom keybinding through gsettings, reusing the same slot on re-runs so it never piles up duplicates. A bare install-hotkey keeps an already-chosen key; only --key moves it.

On other desktops, add the shortcut yourself (System Settings → Keyboard → Shortcuts → Custom Shortcuts → Add) with this command — use the full path to the binary inside your venv:

/path/to/aparte/.venv/bin/aparte toggle --target paste

Then assign a key (e.g. a spare key or Super+Space). Direct paste needs xdotool on X11 or wtype on Wayland; otherwise use --target copy and paste with Ctrl+V. Desktop notifications show when recording starts and stops.

Open Setup in aparte desktop to check the binding: the Keyboard shortcut card shows whether the shortcut is bound and to which key, the one-command auto-bind, and the exact toggle command to bind by hand — each with a copy button.

Create and inspect your config:

aparte config init     # write a default config.json
aparte config path     # print its location
aparte config show     # print the active (merged) config

There is no config set command. To change settings persistently, edit the JSON file printed by aparte config path, or use the Settings panel in aparte desktop — it writes to the same file and applies immediately, including to the global-hotkey flow.

Configuration

Environment variables:

APARTE_TRANSCRIBER=auto
APARTE_RECORDER=auto
APARTE_MODEL=small
APARTE_DEVICE=auto
APARTE_COMPUTE_TYPE=auto
APARTE_LANGUAGE=
APARTE_POLISH_BACKEND=heuristic
APARTE_PASTE_MODE=clipboard
APARTE_MICROPHONE=
APARTE_RUNTIME_DIR=
APARTE_OLLAMA_URL=http://127.0.0.1:11434
APARTE_OLLAMA_MODEL=llama3.1:8b
APARTE_WHISPER_CPP=
APARTE_CONFIG=

APARTE_DEVICE controls the faster-whisper compute device (auto, cpu, or cuda). When a GPU is detected but its CUDA runtime is missing or unusable (libcublas/libcudnn not found), transcription automatically falls back to CPU with int8, so it works out of the box on machines without a CUDA install. Force CPU with APARTE_DEVICE=cpu to skip the GPU probe entirely.

Polish backends:

  • heuristic: fully local, no model required, good enough for punctuation and capitalization cleanup.
  • ollama: local LLM rewrite through Ollama, much better for fillers, backtracking, tone, and context.

System tray icon

Running the desktop app puts an Aparté icon in the system tray: three bars at rest, a filled disc while the microphone is open, and a menu to open the app, copy the last dictation, jump to Settings, or quit.

It relies on PyGObject and the AppIndicator typelib, which are system packages rather than pip ones:

sudo apt install python3-gi gir1.2-ayatanaappindicator3-0.1

./scripts/install-linux.sh --with-system-deps installs them for you, and the script creates the virtualenv with --system-site-packages so it can see them.

A virtualenv created before this change cannot see them, but it does not need rebuilding — flip one line in .venv/pyvenv.cfg, which keeps the multi-gigabyte Whisper and CUDA packages already installed:

include-system-site-packages = true

Without the bindings, Aparté starts exactly as it did before, and aparte doctor tells you what is missing.

Recent dictations

The last five dictations sit under the action bar in the desktop app; click one to copy it. From a terminal, aparte last prints the most recent one and aparte last --target paste re-inserts it into the focused window.

They live in the runtime directory ($XDG_RUNTIME_DIR/aparte, which is tmpfs and wiped when you log out), because a dictation can carry a password or a private message. Tick Keep history between sessions in Settings — or set history_persist in the config — to write them to ~/.local/state/aparte instead, in a file only you can read.

Every Aparté process shares that one store, so a dictation made through the global hotkey shows up in the app, and vice versa, without either one having to be running for the other.

Insertion modes (paste_mode in the config, or How to insert under Hardware in the desktop app). Every mode copies the dictation to the clipboard first, so it is never lost when the insertion lands somewhere unexpected:

  • clipboard (default): one atomic Ctrl+V. Right nearly everywhere.
  • terminal: Ctrl+Shift+V — terminals ignore Ctrl+V entirely.
  • direct: types the text out. For apps that refuse a synthetic paste (LibreOffice, some Electron apps). Slower, and a stray click mid-insertion can scatter it.

Choosing a microphone

Input device, under Hardware in Settings, lists what ALSA can capture from — pick one, or leave it on the system default. Refresh rebuilds the list without closing the panel, for a microphone plugged in after opening it. A device that has since been unplugged stays in the list, marked as such, rather than being silently swapped for another one.

It applies to the global shortcut and to the terminal commands (microphone in the config, an ALSA name such as plughw:CARD=Mini,DEV=0). The desktop app's Talk button records through the browser, so it follows whichever microphone the browser is set to.

Tick Beep on start and stop (beep) for two short tones — a high one when the microphone opens, a lower one when it closes. It is off by default; turn it on if you dictate with the global shortcut without watching the screen.

Preview while you speak

Preview while dictating (live_preview, on by default) shows the transcript building up in the editor instead of leaving you talking into the void. Roughly once a second, whatever has been recorded so far is transcribed again from the start and the result replaces the previous pass — which is also why the text corrects itself as you go: Whisper revises its own guesses once it has heard the end of the sentence. Preview text is shown in lighter ink and the action buttons stay off, because it is not the final version yet; auto-polish only runs at the end, on the final transcript.

Never more than one pass at a time: the next one is scheduled when the previous one comes back. On a slow machine that means fewer previews, never a queue. Even so, without a GPU this keeps one core busy for as long as you speak — untick the setting if the machine struggles. As a side effect, the first preview loads the Whisper model while you are still talking, so the wait after you stop is shorter.

The shortcut reuses the running app's model

Pressing the global shortcut used to start a fresh process that read the Whisper model off disk on every dictation, while the desktop app already held it in memory. The shortcut now hands its audio to that running app when one answers on the loopback address: 0.26 s instead of 1.53 s for the same ten seconds of audio.

Nothing leaves the machine — it is the same local address the browser talks to. When the desktop app is not running, the shortcut loads its own model exactly as before, so dictation never depends on it. Delegation is also skipped when an APARTE_* transcription override is set in the environment, since the running app reads the config file and would ignore it.

Invented subtitle credits are removed

Whisper was trained on subtitled video. On silence — the tail of a dictation, a pause, a microphone picking up nothing — it does not return an empty string: it fills the gap with a subtitling credit seen thousands of times during training. In French the usual one is Sous-titres réalisés par la communauté d'Amara.org.

Aparté strips the known credits from every transcript, whichever path produced it. Credits carrying a domain or a broadcaster name are removed wherever they appear; generic video sign-offs such as Merci d'avoir regardé cette vidéo, which someone writing a video script may genuinely dictate, are only removed when they make up the whole transcript. When in doubt nothing moves — a normal dictation comes back unchanged, and Amara.org on its own is deliberately not in the list.

French typography

Aparté is built for dictating in French, so the formatting rules follow French typography rather than the English ones:

  • a non-breaking space before ? ! ; and : — but not inside https:// or 14:30
  • « » instead of straight double quotes, when they pair up
  • a typographic apostrophe: l'amil’ami
  • standalone i is left alone (upper-casing it is the English pronoun rule)

Which set applies follows the Dictation language setting. On Auto, the language is guessed from the text itself, so French typography works without setting anything — but pinning the setting to Français is more reliable, and it also stops Whisper from drifting to another language.

Set "nonbreaking_spaces": false in the config to use ordinary spaces instead of non-breaking ones, for apps that handle them poorly.

Numbers dictated in words become digits (numbers_from, French only). Whisper already writes digits about half the time; the point is that the same sentence dictated twice comes out the same way. The setting is the threshold below which a number stays in words — 10 by default, which is the French rule:

  • "vingt-deux personnes" → "22 personnes", "quatre-vingt-dix-sept" → "97", "l'an deux mille vingt-six" → "l'an 2026" (a year keeps its four digits together; the thousands separator starts at five)
  • times and percentages always become digits, whatever the threshold: "quatorze heures trente" → "14 h 30", "vingt pour cent" → "20 %"
  • "deux millions" keeps its word — "2 millions", not "2000000"
  • septante, huitante, octante and nonante are understood too
  • an article is never a number: "un chien" stays put, "vingt et un chiens" becomes "21 chiens", and "des mille et des cents" is left alone
  • anything that doesn't parse as a valid number is left exactly as dictated

Out of scope for now: decimals (the spoken "virgule" is turned into a comma before numbers are read), ordinals ("premier" must not become "1er" in "premier ministre"), and English.

Two settings decide how far the formatting goes:

  • Very short dictations (short_text_words, off by default): below this many words the dictation comes out as spoken — no leading capital, no final period. A search field and a one-word answer are not sentences.
  • Trailing space (trailing_space, off by default): ends every dictation with a space, so a second one does not land glued to the first.

Filler word removal (cleanup_level) strips the hesitations: "euh" and "heu" at every level, plus verbal tics such as "ben", "genre" and "tsé" — or "like", "basically", "actually" in English — at the high level.

Recorder backends:

  • auto: try Python sounddevice, then arecord.
  • sounddevice: Python recording backend.
  • arecord: ALSA command-line recorder from alsa-utils.

Persistent config lives at ${XDG_CONFIG_HOME}/aparte/config.json, or ~/.config/aparte/config.json when XDG_CONFIG_HOME is not set. Override it with APARTE_CONFIG=/path/to/config.json.

Example:

{
  "default_style": "neutral",
  "cleanup_level": "medium",
  "language": "en",
  "hotwords": ["Playwright", "Wayland", "PipeWire"],
  "replacements": {
    "whisper flow": "Wispr Flow",
    "pipe wire": "PipeWire",
    "my project": "MyProject"
  },
  "snippets": {
    "signature": "Best,\nAlexandre"
  }
}

With that config, dictating slash signature expands the snippet, and dictated terms such as pipe wire are rewritten with the preferred spelling.

Teaching Aparté your vocabulary

Three settings sit under My dictionary, and they act at three different moments:

Setting Config key When it acts
My words hotwords before transcription — biases Whisper itself
Corrections replacements after, on the text
Spoken shortcuts snippets after, expanding slash <name> into ready-made text

hotwords and replacements are two different tools, not two ways of doing the same thing. My words is a plain list of names — clients, tools, colleagues — handed to Whisper up front, so it leans toward those spellings when the audio is ambiguous. You do not need to have seen the mistake first. Corrections is the safety net for what slips through anyway.

Measured on real speech: without the word list, PipeWire and Mailpoet came out as pipe wire and mail poète; with it, both were spelled correctly, casing included. Three names in the same sentence (Playwright, Wayland, Claude) were already correct without any help — the list is for what actually fails, not for everything you own.

Two caveats. hotwords only exists in faster-whisper; with openai-whisper or whisper.cpp the setting is quietly ignored rather than promising what the backend cannot deliver. And a word list makes Whisper more likely to hear those words — on silence, a list containing PipeWire produced PipeWire.com out of nothing. Keep the list to words you actually say.

Corrections takes one entry per line, heard = written. A line without an = is refused, with its line number, rather than being dropped silently. Spoken shortcuts takes the same form, except the text may continue on the following lines — that is how a multi-line signature is written.

Desktop app

aparte desktop starts a local server on 127.0.0.1 and opens the browser. The interface is a focused, single-screen app:

  • a large Talk button (browser microphone recording as WAV PCM, so no hard dependency on ffmpeg) that records, transcribes, and auto-polishes
  • a transcript editor with Polish, Copy, Insert, and audio import
  • a live preview: the text appears as you speak and keeps correcting itself until you stop
  • a model toggle (small = accurate, base = fast); each model loads once and is cached, so switching is instant after first use
  • a Settings panel (gear icon) ordered by how often a setting is actually touched: Dictation (language, live preview, style, filler-word removal), My dictionary (my words, corrections, spoken shortcuts) and French typography are open on arrival; Hardware (input device, beep, how to insert) and Advanced (default model, compute device, formatting engine, history) are folded into native <details>. Saved to the config file and applied immediately, including to the global-hotkey dictation flow
  • a Configuration & diagnostics panel that shows, with green/red status, what is installed vs missing (Whisper backend, GPU, microphone, paste/clipboard, notifications) and the exact command to fix each gap — copy-paste onboarding for any Linux user

The interface is bilingual (English / French) with a language switch in the top bar; it defaults to the browser language. It follows your desktop's light or dark theme automatically, and the whole keyboard path works: Tab reaches every control with a visible focus ring, Esc closes a panel, and animations are skipped when your system asks for reduced motion.

The frontend lives in src/aparte/assets/ (index.html, app.css, app.js, i18n.js, logo.svg) and is served as static files, with no build step and no library, so it is easy to contribute to. The design system it follows is documented in DESIGN.md, and the product direction behind it in PRODUCT.md.

Desktop notifications

The hotkey dictation flow (toggle and dictate) shows native Linux notifications via notify-send so you can tell when recording starts, when transcription is running, and when text was inserted or copied — useful when the command is bound to a global shortcut and no terminal is visible. Install it with sudo apt install libnotify-bin if notify-send is missing; it is optional and dictation works without it.

This approach avoids GTK/Qt packaging friction while staying Linux-compatible.

Contributing

Contributions are welcome — see CONTRIBUTING.md for the development setup, how to run the tests, and the code layout. The desktop UI is plain HTML/CSS/JS in src/aparte/assets/ with no build step.

License

Aparté is released under the MIT License. It is an independent, open-source project, not affiliated with the commercial Wispr Flow product, nor with the similarly named Murmure project.

About

Aparté (previously Murmur) is a local-first dictation app for Linux. It can run as a CLI, as a command bound to a global keyboard shortcut, or as a lightweight local desktop web app.

Topics

Resources

License

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors