Turn incoming text into speech while the text is still arriving.
A Linux command-line bridge from incremental UTF-8 stdin to Cartesia or ElevenLabs, with immediate PCM playback through mpv. Use it from a pipe, Speech Dispatcher, your clipboard, or an opt-in OpenCode integration.
Русский · Installation · Configuration · Troubleshooting
- Streams in both directions: sends text over WebSockets and plays arriving audio without waiting for stdin to close.
- Two selectable providers: Cartesia Sonic 3.6 with the Russian Sergei voice, or ElevenLabs v4 Turbo. Credentials stay outside the repository.
- Desktop controls: read copied text, stop active and queued speech, and change playback speed while speaking.
- Readable clipboard text: clean Markdown links, headings, tables, entities and decorative citations while preserving useful prose and inline terms.
- Shared playback: serialize this project's speech jobs instead of playing both providers over one another.
- Explicit failures: no automatic provider fallback or replay after an ambiguous failure.
incremental text ──► tts-stream ──► provider WebSocket ──► PCM ──► mpv
▲
provider selection
clipboard ──► speak-text ──► Speech Dispatcher ──► provider adapter
Streaming input is different from streaming audio. tts-stream consumes
text incrementally. speak-text first reads the complete input and submits it
to Speech Dispatcher; its audio still streams. Choose tts-stream when speech
must begin before the producer finishes writing.
GitHub Releases
provide native Arch/pacman (.pkg.tar.zst), Debian/Ubuntu (.deb), and
RPM (.rpm) packages. Follow the native package guide
for installation, configuration, and removal.
For a user-local source installation, with Python 3.11+ and mpv installed:
git clone https://github.com/VibeProgramm/speech-stream.git
cd speech-stream
python3 install.py install
export PATH="$HOME/.local/bin:$PATH"See the Linux installation guide for dependencies, dry-run, and removal. Speech Dispatcher integration is a separate manual setup. Configure your key using the private credential-file setup, then select a provider explicitly. These examples use Cartesia:
speech-provider cartesia
printf '%s\n' 'Привет! Это потоковая озвучка.' | tts-streamAn incremental producer can keep stdin open while speech plays:
python3 -u - <<'PY' | tts-stream
import time
print("Первая фраза уже готова. ", end="", flush=True)
time.sleep(3)
print("А это продолжение потока.", flush=True)
PYProvider buffering and network conditions affect when sound actually starts; the three-second pause is a demonstration, not a latency guarantee.
| Command | Purpose |
|---|---|
tts-stream |
Speak incremental stdin using the selected provider. |
tts-cartesia-stream |
Use Cartesia directly. |
tts-elevenlabs-stream |
Use ElevenLabs directly. |
speak-text |
Read complete stdin through Speech Dispatcher. |
speak-clipboard |
Read explicitly copied text on Wayland. |
stop-speech |
Stop speech and invalidate older queued jobs. |
speech-speed faster / slower |
Adjust speed in 0.1× steps. |
speech-speed reset / status |
Restore 1.0× or print the saved speed. |
speech-provider status |
Print the selected provider. |
speech-provider cartesia / elevenlabs |
Stop speech and switch provider. |
See desktop integration for Speech Dispatcher and KDE shortcuts. Speed is a local playback setting, from 0.5× to 3.0×; it does not resynthesize speech.
Speech Stream is a standalone backend. Live narration through
opencode-talk requires its
opt-in incremental-stdin support, proposed in
upstream PR #3.
That PR is not merged as of November 5, 2026. Installing the upstream default
branch alone does not establish support for live text deltas.
The OpenCode guide explains the command contract, settings, main-session filtering, and how to return to completed-text narration.
- Linux user sessions with Python, mpv, and network access. Clipboard support requires Wayland; KDE is an optional shortcut frontend. No Windows or macOS support is claimed.
- Remote synthesis requires your own provider account and available quota. Text leaves your machine; this is not an offline TTS engine.
- The supplied defaults target Russian. Voice/model availability and provider behavior can change independently of this project.
- Each job has a 10,000-character limit. Whole-word handling can make the spoken prefix shorter. Upstream clients may impose smaller limits of their own.
- Long input gaps and provider context lifetimes are bounded; this is not an unlimited idle connection. See timeouts.
- A failed or cancelled stream may already have spoken part of its input. Nothing can retract that audio; retrying the same input manually repeats it.
- Offline tests exercise local protocol and process behavior. They do not prove provider availability, pronunciation, or the quality of your audio setup.
| Guide | Contents |
|---|---|
| Installation | Dependencies, user-local layout, removal. |
| Native packages | pacman, Debian, and RPM installation and package builds. |
| Configuration | Credentials, providers, voices, paths. |
| Architecture | Text boundaries, WebSockets, PCM, cancellation. |
| Desktop | Speech Dispatcher, clipboard, KDE controls. |
| OpenCode | Optional plugin integration and its status. |
| Troubleshooting | Diagnose the failing layer. |
| Development | Offline tests and live validation scope. |
| Release validation | Review rounds, regressions, and installed live checks. |
| Releasing | Main-push releases, squash merges, versions, and recovery. |
The bridge sends the text you submit to the selected cloud provider. It does not deliberately save transcripts or audio files; debug events contain timing and counts rather than text. Provider-side retention, clipboard history, calling applications, and Speech Dispatcher diagnostics have separate privacy behavior. See Security for the full boundary.
Contributions and reproducible bug reports are welcome. Licensed under MIT. Changelog.