Skip to main content

Push-to-talk voice dictation, fully offline: faster-whisper STT + local Ollama cleanup

Project description

flow_local

CI

Push-to-talk voice dictation into any app — fully local, fully offline.

Download

Platform Get it
Windows Installer (.exe)
macOS .dmg
Linux AppImage or pipx install flow-local

Grab the latest build from the Releases page. Installers are unsigned — Windows will show a SmartScreen "unknown publisher" warning (More info → Run anyway) and macOS needs right-click → Open the first time (Gatekeeper). Already have Python? pipx install flow-local works everywhere.

  • STT: faster-whisper (large-v3-turbo for English, Finnish-NLP/whisper-large-finnish-v3-ct2 for Finnish)
  • Cleanup: local Ollama model rewrites the raw transcript — removes fillers, applies self-corrections, fixes punctuation
  • Output: pasted into the focused window via clipboard + Ctrl+V / Cmd+V (old clipboard restored)

Platform support

Platform Status Notes
Windows ✅ Supported Primary development platform, tested end-to-end
macOS 🧪 Should work Grant Accessibility permission (System Settings → Privacy) so global hotkeys work; paste uses Cmd+V
Linux 🧪 Should work X11 only (pynput can't capture global hotkeys under Wayland); needs PortAudio (libportaudio2) and a clipboard tool (xclip/xsel)

Global hotkeys use pynput, and autostart, hotkeys, and paste all dispatch per-OS, so the code paths are genuinely cross-platform. Windows is tested end-to-end; macOS/Linux are expected to work but haven't been hardware-tested — reports welcome. CI runs lint + unit tests on all three.

Development

Running from source instead of the installer — for contributing, or a platform without a packaged build yet.

Managed with uv. You also need Ollama for transcript cleanup and command mode — plain dictation still works without it, falling back to the raw transcript.

# 1. Start Ollama and pull the cleanup model (default: qwen2.5:7b)
ollama serve                 # skip if it already runs as a background service
ollama pull qwen2.5:7b

# 2. Install and run
uv sync
uv run flow-local

No config-file setup required: on first run the app creates a config.json (and glossary.json) for you, seeded from the committed *.example.json files. It's written to your per-user config directory (%APPDATA%\flow-local\ on Windows, ~/Library/Application Support/flow-local/ on macOS, $XDG_CONFIG_HOME/flow-local/ on Linux) — edit it there, or through the tray's Settings UI. If you're working from a repo checkout and want your personal config to live in the repo instead, drop a config.json at the repo root (copy flow_local/config.example.json) and it takes priority. Either way config.json/glossary.json are gitignored. The first run also downloads the Whisper STT model (~1.6 GB).

Dev tooling:

uv sync --dev
uv run ruff check .      # lint
uv run ruff format .     # format
uv run pytest            # unit tests (no mic/GPU/Ollama needed)
uv run python smoke_test.py  # loads Whisper + hits Ollama (needs Ollama; no mic)
uv run python -m flow_local.settings_server  # open the web-based settings UI

CI (GitHub Actions, .github/workflows/ci.yml) runs lint + tests on every push and pull request, across Ubuntu, macOS, and Windows.

Why no Dockerfile: the app is a desktop tool that needs the host microphone, global keyboard hooks, the system tray, the clipboard, and the GPU — none of which a container can reach sensibly. The Ollama dependency is already an external service; if a server deployment is ever needed, the right split is a containerized transcription API + a thin native client.

Releasing

  1. Bump version in pyproject.toml.
  2. Move the CHANGELOG.md "Unreleased" entries under a new ## [X.Y.Z] heading.
  3. git tag vX.Y.Z && git push origin vX.Y.Z — this triggers .github/workflows/release.yml, which builds the Windows/macOS/Linux installers and opens a draft GitHub Release with them attached.
  4. Review the draft, then publish it by hand. Nothing goes live from a tag push alone.
  5. The PyPI upload (publish-pypi) is gated on the pypi GitHub environment and waits for an approval, because a PyPI version is permanent — it can be yanked but never reused or truly withdrawn. Approve it once the artifacts look right. It authenticates via PyPI trusted publishing (OIDC), so there is no API token to rotate.

Hotkeys (config.json)

Keys Action
hold Ctrl+Space dictate, release to transcribe & paste
hold Ctrl+Alt+Space command mode: select text, hold, speak an instruction ("make this formal") — selection is replaced with the result
hold Ctrl+Alt+C compose mode: speak a brief ("email to john, meeting moved to thursday") — a draft is copied to the clipboard, never auto-pasted
hold Ctrl+Alt+O open mode: speak a file you want opened ("the spreadsheet I was messing with yesterday") — a clear match opens directly, an ambiguous one lists numbered candidates (hold again and say the number)
Ctrl+Shift+Space toggle English / Finnish
Ctrl+Alt+R toggle raw mode (skip LLM cleanup)

Edit config.json to change hotkeys, models, or the personal dictionary (words fed to Whisper as spelling hints). Open mode is Windows-only for now: it matches against the Windows Recent-files list plus the directories in open_roots, and only opens documents/media (never executables or scripts).

Tray menu

Right-click the tray icon (on Windows, bottom-right taskbar, maybe behind the ^ chevron):

  • Settings — opens the web-based settings UI
  • Language — toggle English / Finnish
  • Wakeup Beep — toggle the sound played when recording starts
  • Raw mode — toggle the LLM cleanup pass
  • Start on login — checkbox; the label and mechanism are per-OS (registry Run key on Windows, a LaunchAgent on macOS, an XDG .desktop entry on Linux). Hidden on unsupported platforms.
  • Check for updates — opens the GitHub Releases page in your browser
  • Quit

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

flow_local-0.1.0.tar.gz (277.4 kB view details)

Uploaded Source

Built Distribution

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

flow_local-0.1.0-py3-none-any.whl (43.2 kB view details)

Uploaded Python 3

File details

Details for the file flow_local-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for flow_local-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4c7c351e6ab2d891db8c3d013410c94ed5ac514e0d26f64e7d33343c09b8d7f5
MD5 596043ad01821ef4bdf429240c98358d
BLAKE2b-256 65f80b02d1ec396994f1a18bb36117e66d40467847b13c54a45c89ffd0aa860f

See more details on using hashes here.

Provenance

The following attestation bundles were made for flow_local-0.1.0.tar.gz:

Publisher: release.yml on Tonzium/TyprFlow

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

File details

Details for the file flow_local-0.1.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for flow_local-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c22958d34946ea0753c97ae75f21fecf0b42872a1654fa986dcc7d4e5c014783
MD5 e4de2efa1599673cffcf7cf3612ee2fd
BLAKE2b-256 da71352c295ac83571f7159d6ca5566a8785750be9dc76e8182db768fb45f75a

See more details on using hashes here.

Provenance

The following attestation bundles were made for flow_local-0.1.0-py3-none-any.whl:

Publisher: release.yml on Tonzium/TyprFlow

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