Rewrite README; fix fd leak, StopIteration crash, add pip Dependabot
- README.md: full rewrite with architecture, quickstart, config examples, privacy model, and contributing section (deduced from source) - recorder.py: close leaked fd from mkstemp (SEC-2) - gtkui.py: guard next() with default to prevent StopIteration (CQ-4) - dependabot.yml: add pip ecosystem for linux/ deps (SEC-5)
This commit is contained in:
parent
b72936be31
commit
80038a37ea
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -5,3 +5,7 @@ updates:
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
- package-ecosystem: pip
|
||||
directory: /linux
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
539
README.md
539
README.md
@ -1,212 +1,251 @@
|
||||
# Blitztext App Linux
|
||||
# ⚡ Blitztext App Linux
|
||||
|
||||
Blitztext App Linux is a native Linux dictation and writing assistant. Focus any
|
||||
text field, trigger a workflow, speak, and Blitztext types the result back into
|
||||
the application you were already using.
|
||||
**Speak into any text field on your Linux desktop — instantly.**
|
||||
|
||||
It can type a plain transcript, rewrite rough speech with an OpenAI-compatible
|
||||
LLM, route spoken commands to different workflows, benchmark STT engines, and
|
||||
stream live words from a Riva/NIM realtime speech server.
|
||||
Blitztext is a native Linux dictation tool that captures your voice, transcribes it locally with [faster-whisper](https://github.com/SYSTRAN/faster-whisper), optionally rewrites the text through an LLM, and types the result directly into whatever application has focus. Think macOS Dictation, but open-source, extensible, and designed for power users who want full control over their speech-to-text pipeline.
|
||||
|
||||
This is a host desktop app, not a browser app and not a hosted service. The
|
||||
current Linux version is built around GTK, AppIndicator, global hotkeys,
|
||||
`faster-whisper`, optional OpenAI-compatible endpoints, optional Riva/NIM
|
||||
realtime STT, and `xdotool` text delivery.
|
||||
> **Status:** Experimental open-source Linux/X11 desktop app (v1.1.0).
|
||||
> No hosted backend — bring your own models and endpoints.
|
||||
|
||||
> Status: experimental Linux/X11 app. Bring your own local models or endpoints.
|
||||
> No hosted Blitztext backend is included.
|
||||
---
|
||||
|
||||
## Inspiration
|
||||
## Inspiration & Credits
|
||||
|
||||
Blitztext App Linux is inspired by
|
||||
[cmagnussen/blitztext-app](https://github.com/cmagnussen/blitztext-app), the
|
||||
original macOS menu-bar app for turning speech into text and cleaner writing.
|
||||
This repository keeps the spirit of that workflow while implementing a
|
||||
Linux-native version with Linux desktop APIs and Linux-friendly model backends.
|
||||
Blitztext App Linux is inspired by [cmagnussen/blitztext-app](https://github.com/cmagnussen/blitztext-app), the original macOS menu-bar app for turning speech into text and cleaner writing. This Linux version recreates the workflow using Linux-native components:
|
||||
|
||||
## Features
|
||||
| Upstream (macOS) | This project (Linux) |
|
||||
|---|---|
|
||||
| Swift / SwiftUI | Python 3.11+ / GTK 3 |
|
||||
| WhisperKit / CoreML | [faster-whisper](https://github.com/SYSTRAN/faster-whisper) (CTranslate2) |
|
||||
| macOS Accessibility API | `xdotool` (X11) |
|
||||
| Menu bar app | AppIndicator tray + GTK control panel |
|
||||
| — | Riva/NIM realtime WebSocket STT |
|
||||
| — | Voice-keyword routing |
|
||||
| — | Built-in STT benchmark |
|
||||
|
||||
- **Native Linux tray app**: run Blitztext from the system tray, open the GTK
|
||||
control panel, or run it headless with global hotkeys only.
|
||||
- **Plain dictation**: record speech, transcribe it, and type the raw text into
|
||||
the focused X11 window.
|
||||
- **Rewrite workflows**: turn rough speech into a nicer email, improved text, a
|
||||
calmer message, emoji-rich text, or any custom prompt you define.
|
||||
- **Realtime STT streaming**: use a `riva_realtime` STT engine, such as
|
||||
Nemotron ASR Streaming, to type stable words while you are still speaking.
|
||||
- **Voice-keyword routing**: use one routing hotkey and say a workflow keyword
|
||||
at the start or end of your speech to choose the preset.
|
||||
- **Two input styles**: use direct workflow hotkeys, or the modifier workflow:
|
||||
Ctrl+Super to start, Ctrl to stop and type, Alt to stop/type/send, Esc to
|
||||
cancel.
|
||||
- **Push-to-talk option**: hold the start modifier to record and release it to
|
||||
finish.
|
||||
- **Multiple STT engines**: local `faster-whisper`, OpenAI-compatible batch STT
|
||||
endpoints, and Riva/NIM realtime WebSocket STT.
|
||||
- **Multiple LLM engines**: OpenAI-compatible chat endpoints for OpenAI, local
|
||||
vLLM, llama-swap, Ollama `/v1`, LM Studio, Groq, OpenRouter, and similar
|
||||
servers.
|
||||
- **STT benchmark tab**: compare configured STT engines against a reference WAV
|
||||
and transcript.
|
||||
- **Settings UI**: edit workflows, engines, input mode, microphone, language,
|
||||
benchmark files, autostart, logs, and About metadata.
|
||||
- **About page**: shows the app version, source repository, changelog, license,
|
||||
and legal notes.
|
||||
- **Debian package**: build a local `.deb` with the launcher, icon, bundled
|
||||
Python environment, and system dependency declarations.
|
||||
Credit to the [SYSTRAN/faster-whisper](https://github.com/SYSTRAN/faster-whisper) project for the local Whisper inference engine, and to the [pynput](https://pypi.org/project/pynput/) library for global hotkey handling.
|
||||
|
||||
## How It Works
|
||||
---
|
||||
|
||||
```text
|
||||
Batch workflows
|
||||
---------------
|
||||
focused app -> global hotkey -> record mic -> STT engine
|
||||
|
|
||||
+-> mode "transcribe" -> type/paste text
|
||||
|
|
||||
+-> mode "rewrite" -> LLM -> type/paste text
|
||||
## Core Functionality & Key Differentiators
|
||||
|
||||
Realtime workflow
|
||||
-----------------
|
||||
focused app -> stream workflow -> mic PCM chunks -> Riva/NIM WebSocket
|
||||
|
|
||||
+-> stable partial text -> xdotool
|
||||
### What it does
|
||||
|
||||
```
|
||||
Batch: hotkey → record mic → faster-whisper (local) → [optional LLM rewrite] → xdotool types it
|
||||
Stream: hotkey → mic PCM chunks → Riva/NIM WebSocket → live words typed as you speak
|
||||
```
|
||||
|
||||
Blitztext remembers the focused X11 window when recording starts, then delivers
|
||||
the final text back to that window. Delivery can be direct typing or clipboard
|
||||
paste, depending on your configuration.
|
||||
1. **Focus any text field** — terminal, browser, email client, IDE, chat app.
|
||||
2. **Press a hotkey** (or use modifier keys, or click the tray menu).
|
||||
3. **Speak naturally.**
|
||||
4. **Text appears** where your cursor is — plain transcript, polished email, calmed-down message, or emoji-enriched text.
|
||||
|
||||
### What makes it different
|
||||
|
||||
- **Runs on the host, not in a browser.** Because it uses `xdotool`, it can type into *any* X11 application — not just a web page or Electron app.
|
||||
- **Fully local STT.** Batch transcription via `faster-whisper` never leaves your machine. No cloud account needed for basic dictation.
|
||||
- **Pluggable engines.** Configure multiple STT and LLM backends as named presets — local `faster-whisper`, remote OpenAI-compatible batch endpoints, Riva/NIM realtime WebSocket servers, and any OpenAI-compatible chat API (OpenAI, vLLM, llama-swap, Ollama, LM Studio, Groq, OpenRouter).
|
||||
- **Voice-keyword routing.** One hotkey, multiple workflows. Say "nicer email" at the start or end of your speech and the email-rewrite preset activates automatically (fuzzy-matched, ASR-tolerant).
|
||||
- **Quality gate.** Silent clips, too-short recordings, and Whisper hallucinations ("Thank you.", "Untertitel…") are caught and rejected before they reach your text field.
|
||||
- **Realtime streaming.** Connect a Riva/NIM realtime STT server and see stable words typed live as you speak.
|
||||
- **Built-in benchmarking.** Compare all your configured STT engines against a reference WAV + transcript to find the fastest and most accurate.
|
||||
|
||||
---
|
||||
|
||||
## Target Use Cases
|
||||
|
||||
| Scenario | How Blitztext helps |
|
||||
|---|---|
|
||||
| **Quick replies** | Dictate an email or chat message instead of typing it |
|
||||
| **Rough-to-polished** | Speak freely, let the LLM rewrite it into a professional email |
|
||||
| **Multilingual dictation** | faster-whisper supports 99 languages; set `language = "de"` or `"en"` |
|
||||
| **Local-only transcription** | Use `faster-whisper` with no network calls at all |
|
||||
| **Live captioning** | Stream mode types words as you speak (with a Riva/NIM server) |
|
||||
| **Voice-driven workflows** | Trigger different presets by speaking a keyword |
|
||||
| **STT engine comparison** | Benchmark tab compares speed and accuracy across all configured engines |
|
||||
| **GPU or CPU** | Works on CPU (`int8`) out of the box; add a CUDA CTranslate2 build for GPU |
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- Linux desktop running an **X11 session**.
|
||||
- Python 3.11+ when running from source.
|
||||
- `xdotool` for text delivery.
|
||||
- `notify-send` from `libnotify-bin` for desktop notifications.
|
||||
- One recorder: `pw-record`, `parecord`, or `arecord`.
|
||||
- `python3-gi` and AppIndicator/Ayatana typelibs for the GTK tray.
|
||||
- Optional: CUDA-capable `faster-whisper`/CTranslate2 setup for GPU local STT.
|
||||
- Optional: an OpenAI-compatible chat endpoint for rewrite workflows.
|
||||
- Optional: a Riva/NIM realtime server for live streaming STT.
|
||||
- **Linux desktop with an X11 session** (Wayland needs `ydotool`/`wtype` — not yet supported)
|
||||
- **Python 3.11+** (for source installs)
|
||||
- **Host tools:**
|
||||
|
||||
On Ubuntu/Debian:
|
||||
```bash
|
||||
sudo apt install xdotool libnotify-bin pipewire-bin python3-gi
|
||||
```
|
||||
|
||||
- `xdotool` — text delivery into the focused window
|
||||
- `libnotify-bin` — desktop notifications (`notify-send`)
|
||||
- `pipewire-bin` — microphone recording (`pw-record`); alternatives: `pulseaudio-utils` (`parecord`) or `alsa-utils` (`arecord`)
|
||||
- `python3-gi` — GTK 3 / AppIndicator system tray
|
||||
|
||||
- **Optional:** An OpenAI-compatible chat endpoint for rewrite workflows
|
||||
- **Optional:** A Riva/NIM realtime server for live streaming STT
|
||||
|
||||
---
|
||||
|
||||
## Installation & Setup
|
||||
|
||||
### Option A — Debian Package (recommended for Ubuntu/Debian)
|
||||
|
||||
Build a `.deb` and install it. No pip, no network needed at install time:
|
||||
|
||||
```bash
|
||||
sudo apt install xdotool libnotify-bin pipewire-bin python3-gi
|
||||
```
|
||||
|
||||
Wayland is not the primary target yet. The current app uses `xdotool`, so use an
|
||||
X11 session for reliable typing into other applications.
|
||||
|
||||
## Install
|
||||
|
||||
### Debian Package
|
||||
|
||||
The recommended Ubuntu/Debian path is to build and install the local package:
|
||||
|
||||
```bash
|
||||
cd linux
|
||||
bash packaging/build-deb.sh
|
||||
git clone https://github.com/mARTin-B78/blitztext-app-linux.git
|
||||
cd blitztext-app-linux/linux
|
||||
bash packaging/build-deb.sh # → dist/blitztext_<ver>_<arch>.deb
|
||||
sudo apt install ./dist/blitztext_*.deb
|
||||
```
|
||||
|
||||
This installs Blitztext under `/opt/blitztext`, adds a desktop launcher, installs
|
||||
the app icon, and provides the `blitztext` command.
|
||||
This installs Blitztext to `/opt/blitztext`, adds a **Blitztext** entry to your application menu, installs the app icon, and pulls in system dependencies automatically. Remove with `sudo apt remove blitztext`.
|
||||
|
||||
Start it with:
|
||||
### Option B — Run from Source (venv)
|
||||
|
||||
```bash
|
||||
blitztext tray
|
||||
```
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
cd linux
|
||||
git clone https://github.com/mARTin-B78/blitztext-app-linux.git
|
||||
cd blitztext-app-linux/linux
|
||||
./install.sh
|
||||
```
|
||||
|
||||
`install.sh` creates a `.venv` with `--system-site-packages` (so it sees the system `python3-gi` for the GTK tray), installs dependencies from `requirements.txt`, and writes the default config.
|
||||
|
||||
> **Important:** Build the venv from `/usr/bin/python3`, not a conda/miniforge Python.
|
||||
> A conda Python can't see the apt-installed `python3-gi`, so the tray won't start.
|
||||
> The `.deb` package avoids this issue entirely.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The only environment variable needed is for rewrite workflows that use a cloud LLM:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=sk-... # only if using OpenAI or a keyed endpoint
|
||||
```
|
||||
|
||||
The config file (`~/.config/blitztext/config.toml`) references environment variable *names*, never the keys themselves. Local STT and local LLM endpoints typically require no key.
|
||||
|
||||
---
|
||||
|
||||
## Quickstart Tutorial
|
||||
|
||||
**Goal:** Go from zero to dictating text into a terminal in under 5 minutes.
|
||||
|
||||
### 1. Install
|
||||
|
||||
```bash
|
||||
# Ubuntu/Debian — install host tools
|
||||
sudo apt install xdotool libnotify-bin pipewire-bin python3-gi
|
||||
|
||||
# Clone and set up
|
||||
git clone https://github.com/mARTin-B78/blitztext-app-linux.git
|
||||
cd blitztext-app-linux/linux
|
||||
./install.sh
|
||||
```
|
||||
|
||||
### 2. Launch
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m blitztext tray
|
||||
```
|
||||
|
||||
`install.sh` creates a virtual environment with `--system-site-packages` so the
|
||||
app can see the system `python3-gi` package used by GTK/AppIndicator.
|
||||
A microphone icon appears in your system tray. The first launch downloads the Whisper `small` model (~460 MB) — wait for the "Ready" notification.
|
||||
|
||||
## Run
|
||||
### 3. Dictate
|
||||
|
||||
1. **Open a text editor** (gedit, VS Code, a terminal, a browser text field — anything).
|
||||
2. **Click in the text field** so it has focus.
|
||||
3. **Press `Ctrl+Super`** (Ctrl + Windows key) to start recording.
|
||||
4. **Speak** your text naturally.
|
||||
5. **Press `Ctrl`** to stop, transcribe, and type the result.
|
||||
|
||||
That's it. The transcribed text appears where your cursor was.
|
||||
|
||||
### 4. Try a rewrite workflow
|
||||
|
||||
```bash
|
||||
blitztext tray # tray app with workflow menu, default installed mode
|
||||
blitztext gui # GTK control panel
|
||||
blitztext run # headless hotkey daemon
|
||||
blitztext config-path # print config file path
|
||||
blitztext --version # print app version
|
||||
export OPENAI_API_KEY=sk-... # or point at a local LLM in Settings
|
||||
```
|
||||
|
||||
From a source checkout, use:
|
||||
1. Press `Ctrl+Super` → speak something rough like "hey john can you send me the report"
|
||||
2. Press `Ctrl` — the text appears as a plain transcript.
|
||||
|
||||
Now try with voice routing:
|
||||
|
||||
1. Press `Ctrl+Alt+Space` → say **"nicer email** hey john can you send me the report"
|
||||
2. Press `Ctrl` — Blitztext detects the keyword, runs the "Nicer email" rewrite, and types a polished email.
|
||||
|
||||
### 5. Explore Settings
|
||||
|
||||
Click the ⚙️ gear icon in the panel header, or right-click the tray → **Settings…**
|
||||
|
||||
- **Presets** — edit workflows, hotkeys, prompts, keywords
|
||||
- **Engines** — manage STT and LLM backends, check online status, run tests
|
||||
- **Input** — switch between modifier keys and direct hotkeys
|
||||
- **General** — choose microphone, output mode, language, autostart
|
||||
- **Benchmark** — compare STT engines with a reference WAV
|
||||
- **Log** — inspect runtime messages
|
||||
- **About** — version, changelog, license
|
||||
|
||||
---
|
||||
|
||||
## CLI Reference
|
||||
|
||||
```bash
|
||||
blitztext tray # System tray + hotkeys (default)
|
||||
blitztext gui # GTK control panel window
|
||||
blitztext run # Headless daemon, hotkeys only
|
||||
blitztext transcribe f.wav # One-shot transcription, prints text
|
||||
blitztext config-path # Print config file location
|
||||
blitztext --version # Print version
|
||||
```
|
||||
|
||||
From a source checkout, prefix with `.venv/bin/python -m`:
|
||||
|
||||
```bash
|
||||
cd linux
|
||||
.venv/bin/python -m blitztext tray
|
||||
.venv/bin/python -m blitztext gui
|
||||
.venv/bin/python -m blitztext run
|
||||
.venv/bin/python -m blitztext transcribe sample.wav
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Default Workflows
|
||||
|
||||
| Workflow | Mode | Default trigger | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| Transcribe | `transcribe` | voice-routing default | Types the raw transcript |
|
||||
| Nicer email | `rewrite` | `Ctrl+Alt+E` | Turns rough notes into a polished email |
|
||||
| Improve text | `rewrite` | `Ctrl+Alt+I` | Cleans spelling, grammar, and wording |
|
||||
| Calm down | `rewrite` | `Ctrl+Alt+C` | Rewrites frustrated speech into a calm message |
|
||||
| Add emojis | `rewrite` | `Ctrl+Alt+J` | Keeps the text and adds fitting emojis |
|
||||
| STT Streaming | `stream` | user-created / optional | Types live words from realtime STT |
|
||||
| Hotkey | Workflow | Mode | What it does |
|
||||
|---|---|---|---|
|
||||
| `Ctrl+Alt+Space` | *(voice routing)* | auto | Routes to a preset by spoken keyword |
|
||||
| `Ctrl+Alt+E` | Nicer email | `rewrite` | Turns rough speech into a polished email |
|
||||
| `Ctrl+Alt+I` | Improve text | `rewrite` | Proofreads and improves wording |
|
||||
| `Ctrl+Alt+C` | Calm down | `rewrite` | Rewrites frustrated speech into a calm message |
|
||||
| `Ctrl+Alt+J` | Add emojis | `rewrite` | Adds fitting emojis to the text |
|
||||
|
||||
The default config uses voice-keyword routing as the primary input style. Press
|
||||
the routing hotkey, speak normally, and optionally say a preset keyword such as
|
||||
"nicer email" or "calm down" at the beginning or end of the utterance.
|
||||
With the default `modifiers` input mode:
|
||||
|
||||
| Key | Action |
|
||||
|---|---|
|
||||
| `Ctrl+Super` | Start recording |
|
||||
| `Ctrl` | Stop → transcribe → type |
|
||||
| `Alt` | Stop → transcribe → type → press Enter |
|
||||
| `Esc` | Cancel (discard recording) |
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Blitztext writes its configuration to:
|
||||
All settings live in `~/.config/blitztext/config.toml`. Edit through the Settings UI or directly as TOML.
|
||||
|
||||
```text
|
||||
~/.config/blitztext/config.toml
|
||||
```
|
||||
|
||||
You can edit it through **Settings** or directly as TOML. The settings window
|
||||
contains:
|
||||
|
||||
- **Presets**: workflow name, icon, description, mode, hotkey, keywords, prompt,
|
||||
model override, and temperature override.
|
||||
- **Engines**: STT and LLM engine presets, status checks, and STT test.
|
||||
- **Input**: modifier mode, direct hotkey mode, push-to-talk, microphone, output
|
||||
method, typing delay, language, and quality gates.
|
||||
- **General**: notifications, autostart, and app behavior.
|
||||
- **Benchmark**: compare STT engines with a reference WAV and text file.
|
||||
- **Log**: inspect runtime messages.
|
||||
- **About**: version, changelog, source, license, and legal information.
|
||||
|
||||
## STT Engines
|
||||
|
||||
Local transcription uses `faster-whisper`:
|
||||
### Local Whisper (batch STT)
|
||||
|
||||
```toml
|
||||
[stt]
|
||||
active = "Local faster-whisper"
|
||||
|
||||
[[stt_engine]]
|
||||
name = "Local faster-whisper"
|
||||
type = "local"
|
||||
|
||||
[whisper]
|
||||
model = "small"
|
||||
device = "auto"
|
||||
compute_type = "auto"
|
||||
model = "small" # tiny | base | small | medium | large-v3
|
||||
device = "auto" # auto | cuda | cpu
|
||||
compute_type = "auto" # auto | int8 | float16
|
||||
beam_size = 5
|
||||
```
|
||||
|
||||
Batch remote transcription uses OpenAI-compatible `/audio/transcriptions`
|
||||
servers:
|
||||
### Remote batch STT
|
||||
|
||||
```toml
|
||||
[[stt_engine]]
|
||||
@ -214,60 +253,25 @@ name = "faster-whisper-server"
|
||||
type = "openai"
|
||||
url = "http://localhost:8010/v1"
|
||||
model = "Systran/faster-whisper-base"
|
||||
api_key_env = ""
|
||||
```
|
||||
|
||||
Realtime streaming uses a Riva/NIM realtime WebSocket server:
|
||||
### Realtime STT streaming
|
||||
|
||||
```toml
|
||||
[[stt_engine]]
|
||||
name = "Nemotron ASR Streaming"
|
||||
type = "riva_realtime"
|
||||
url = "http://127.0.0.1:8006/v1"
|
||||
model = ""
|
||||
api_key_env = ""
|
||||
```
|
||||
|
||||
Streaming engines are live-only. They are used by workflows with
|
||||
`mode = "stream"`, not by batch transcription or the benchmark tab.
|
||||
|
||||
## Realtime STT Streaming
|
||||
|
||||
To use Nemotron ASR Streaming or another compatible Riva/NIM realtime server:
|
||||
|
||||
1. Start the realtime STT server.
|
||||
2. Open **Settings > Engines**.
|
||||
3. Click **+ Stream** to add the Nemotron ASR Streaming preset.
|
||||
4. Save and restart Blitztext if prompted.
|
||||
5. Create or edit a workflow with `mode = "stream"`.
|
||||
|
||||
Example:
|
||||
|
||||
```toml
|
||||
[general]
|
||||
language = "en-US"
|
||||
|
||||
[stt]
|
||||
active = "Nemotron ASR Streaming"
|
||||
|
||||
[[workflow]]
|
||||
name = "STT Streaming"
|
||||
description = "Live words while you speak."
|
||||
hotkey = "<ctrl>+<alt>+s"
|
||||
mode = "stream"
|
||||
```
|
||||
|
||||
The tested Nemotron ASR Streaming NIM exposes an English `en-US` model. For that
|
||||
server, use `language = "en"` or `language = "en-US"`.
|
||||
|
||||
## Rewrite Engines
|
||||
|
||||
Rewrite workflows send the transcript to an OpenAI-compatible chat endpoint:
|
||||
### LLM rewrite endpoint
|
||||
|
||||
```toml
|
||||
[llm]
|
||||
active = "Default"
|
||||
|
||||
[[llm_engine]]
|
||||
name = "Default"
|
||||
type = "cloud"
|
||||
@ -277,7 +281,7 @@ api_key_env = "OPENAI_API_KEY"
|
||||
temperature = 0.3
|
||||
```
|
||||
|
||||
For local rewriting, point the URL at a local OpenAI-compatible server:
|
||||
For local rewriting, point at a local server:
|
||||
|
||||
```toml
|
||||
[[llm_engine]]
|
||||
@ -286,81 +290,134 @@ type = "local"
|
||||
url = "http://localhost:28080/v1"
|
||||
model = "Qwen3.5-4B"
|
||||
api_key_env = ""
|
||||
temperature = 0.3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Privacy
|
||||
|
||||
Blitztext App Linux does not include a hosted backend. Where your audio or text
|
||||
goes depends on the engines you configure:
|
||||
Blitztext does **not** include a hosted backend. Where your data goes depends on what you configure:
|
||||
|
||||
```text
|
||||
Local STT: your desktop -> local faster-whisper
|
||||
Remote batch STT: your desktop -> configured /audio/transcriptions endpoint
|
||||
Realtime STT: your desktop -> configured Riva/NIM realtime endpoint
|
||||
Rewrite workflows: your desktop -> configured OpenAI-compatible chat endpoint
|
||||
Text delivery: Blitztext -> xdotool -> focused X11 window
|
||||
```
|
||||
Local STT: microphone → local faster-whisper (never leaves your machine)
|
||||
Remote batch STT: microphone → your configured /audio/transcriptions endpoint
|
||||
Realtime STT: microphone → your configured Riva/NIM realtime endpoint
|
||||
Rewrite: transcript → your configured OpenAI-compatible chat endpoint
|
||||
Delivery: text → xdotool → focused X11 window
|
||||
```
|
||||
|
||||
Do not use remote endpoints with sensitive content unless you understand and
|
||||
accept the data handling of those services. See [docs/privacy.md](docs/privacy.md)
|
||||
for more detail.
|
||||
API keys are stored as environment variable *names* in the config, never as values. See [docs/privacy.md](docs/privacy.md) for the full privacy model.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```text
|
||||
```
|
||||
linux/
|
||||
blitztext/ Linux app package: GTK UI, tray, daemon, STT, LLM, config
|
||||
packaging/ Debian packaging, desktop file, app icons
|
||||
README.md Detailed Linux usage guide
|
||||
CHANGELOG.md Linux app changelog
|
||||
docs/ Setup, privacy, roadmap, release, and project notes
|
||||
BlitztextMac/ Legacy/upstream macOS reference code kept for context
|
||||
README.md This Linux-first project overview
|
||||
blitztext/ Python package: GTK UI, tray, daemon, STT, LLM, config
|
||||
packaging/ Debian packaging, desktop entry, app icons
|
||||
install.sh Venv setup script
|
||||
requirements.txt Python dependencies
|
||||
CHANGELOG.md Linux app changelog
|
||||
README.md Detailed Linux usage guide
|
||||
docs/ Setup, privacy, and project documentation
|
||||
.github/ CI workflows, issue templates, Dependabot, secret scan
|
||||
README.md ← you are here
|
||||
```
|
||||
|
||||
## Development
|
||||
---
|
||||
|
||||
Useful checks:
|
||||
## Run on Login
|
||||
|
||||
### Autostart toggle (recommended)
|
||||
|
||||
Open **Settings → General → Launch on login** and enable it. This writes a freedesktop `.desktop` entry to `~/.config/autostart/`.
|
||||
|
||||
### systemd user service
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cp linux/blitztext.service ~/.config/systemd/user/
|
||||
# edit ExecStart if your checkout path differs
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now blitztext
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- **X11 only.** Text delivery uses `xdotool`. Wayland support (`wtype`/`ydotool`) is planned but not implemented.
|
||||
- **No automated tests yet.** Contributions welcome (routing, quality gate, config parsing are all highly testable).
|
||||
- **Realtime streaming** requires a compatible Riva/NIM server.
|
||||
- **Local STT speed** depends on your hardware, Whisper model size, and CTranslate2 build (CPU `int8` by default).
|
||||
- This is experimental software provided as-is.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
||||
|
||||
**Good first contributions:**
|
||||
- Add unit tests for `routing.py`, `quality.py`, `config.py`, `benchmark.py`
|
||||
- Add Linux screenshots
|
||||
- Improve error messages and first-run setup
|
||||
- Document known-good STT/LLM engine configurations
|
||||
- Add Wayland support via `wtype` or `ydotool`
|
||||
|
||||
**Quick development loop:**
|
||||
|
||||
```bash
|
||||
cd linux
|
||||
.venv/bin/python -m py_compile blitztext/*.py
|
||||
.venv/bin/python -m blitztext --version
|
||||
.venv/bin/python -m blitztext config-path
|
||||
./install.sh
|
||||
.venv/bin/python -m py_compile blitztext/*.py # syntax check
|
||||
.venv/bin/python -m blitztext --version # smoke test
|
||||
.venv/bin/python -m blitztext gui # run the GUI
|
||||
```
|
||||
|
||||
Useful docs:
|
||||
Please read [SECURITY.md](SECURITY.md) before reporting vulnerabilities.
|
||||
|
||||
- [linux/README.md](linux/README.md) for the detailed Linux guide.
|
||||
- [docs/setup.md](docs/setup.md) for setup notes.
|
||||
- [linux/CHANGELOG.md](linux/CHANGELOG.md) for app changes.
|
||||
- [ROADMAP.md](ROADMAP.md) for planned work.
|
||||
- [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
|
||||
|
||||
## Current Limits
|
||||
|
||||
- X11 is required for reliable text delivery through `xdotool`.
|
||||
- Realtime streaming depends on a compatible Riva/NIM realtime server.
|
||||
- Rewrite workflows depend on the LLM endpoint you configure.
|
||||
- Local STT speed depends on your `faster-whisper` model, CPU/GPU, and
|
||||
CTranslate2 build.
|
||||
- This is experimental open-source software provided as-is.
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Code is released under the MIT License. See [LICENSE](LICENSE).
|
||||
This project is released under the **MIT License**. See [LICENSE](LICENSE).
|
||||
|
||||
Project names, logos, and app icons are not automatically granted as trademarks
|
||||
or brand assets. See [TRADEMARKS.md](TRADEMARKS.md).
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Blitztext contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
Project names, logos, and app icons are not automatically granted as trademarks or brand assets. See [TRADEMARKS.md](TRADEMARKS.md).
|
||||
|
||||
---
|
||||
|
||||
## Legal / Impressum & Datenschutz
|
||||
|
||||
This is an experimental, non-commercial open-source project, provided as-is under
|
||||
the MIT License without warranty or support. Nothing is sold here and no
|
||||
installation or operation is performed on your behalf.
|
||||
This is an experimental, non-commercial open-source project, provided as-is under the MIT License without warranty or support. Nothing is sold here and no installation or operation is performed on your behalf.
|
||||
|
||||
The companion website (blitztext.de) is operated by Blackboat Internet GmbH:
|
||||
|
||||
- Impressum: https://martin-bierschenk.de/impressum/
|
||||
- Datenschutz / Privacy: https://martin-bierschenk.de/datenschutz/
|
||||
|
||||
|
||||
@ -249,7 +249,8 @@ class App:
|
||||
for nm, r in self._rows.items():
|
||||
cls(nm, None, "dim", "recording")
|
||||
r["pill"].get_style_context().remove_class("rec")
|
||||
r["pill"].set_text(pretty_hotkey(next(w.hotkey for w in self.cfg.workflows if w.name == nm)))
|
||||
wf_match = next((w for w in self.cfg.workflows if w.name == nm), None)
|
||||
r["pill"].set_text(pretty_hotkey(wf_match.hotkey) if wf_match else "")
|
||||
return False # one-shot idle
|
||||
|
||||
# -- panel / settings / lifecycle -----------------------------------------
|
||||
|
||||
@ -6,6 +6,7 @@ available — no Python audio bindings or device configuration required.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
@ -42,7 +43,9 @@ class Recording:
|
||||
"""A single in-progress recording. Start on construction, call stop()."""
|
||||
|
||||
def __init__(self, recorder: str, device: str = ""):
|
||||
self._tmp = Path(tempfile.mkstemp(prefix="blitztext-", suffix=".wav")[1])
|
||||
fd, path = tempfile.mkstemp(prefix="blitztext-", suffix=".wav")
|
||||
os.close(fd)
|
||||
self._tmp = Path(path)
|
||||
argv = list(_RECORDERS[recorder])
|
||||
flag = _DEVICE_FLAG.get(recorder, [])
|
||||
if device and flag:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user