elo-stt-passive
by hexicgrind
README.md
# Elo STT Passive v1.0
Global **push-to-talk speech-to-text** for Windows 11.
Hold **Right Ctrl** to talk (works while the app is minimized or unfocused). On release, audio is sent to [Fish Audio](https://fish.audio) STT, then typed into whichever window has focus—including fullscreen games. Optionally run as an **MCP server** so Claude Desktop, Claude Code, OpenClaw, and similar tools can read your STT history.
## Features
| Feature | Details |
|--------|---------|
| Global hotkey | Right Ctrl hold-to-talk; Right Shift cancels |
| Rolling buffer | Configurable pre/post roll (default **0.5 s**) so words are not clipped |
| Speech gate | Skips the API when only ambient noise is present (distinct soft cue) |
| Audio prep | Normalizes *quiet* speech, then boosts all speech (~**+30%** default, dB-aware) |
| Game-friendly typing | `SendInput` Unicode **key-down / key-up** with configurable delay & hold |
| Parallel jobs | Start a new hold while a previous clip is still processing |
| Soft cues | Distinct low-volume sounds for error, cancel, and no-speech |
| API key safety | Reads `FISH_AUDIO_API_KEY` from the environment only — **never saved to disk** |
| MCP | Query recent results, time windows, ranges, search; timestamps on hold start/end |
| Config | All knobs in `config.ini` next to the program |
## Requirements
- Windows 11 (designed for; other Windows versions may work)
- Python **3.10+**
- A [Fish Audio API key](https://fish.audio/app/api-keys)
## Install
```powershell
cd "C:\Projects\Elo STT Passive\repo"
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
```
### Set the API key (Windows 11)
1. Press **Win**, search for **environment variables**, open **Edit the system environment variables**.
2. **Environment Variables…** → under **User variables** → **New…**
3. Name: `FISH_AUDIO_API_KEY`
Value: your key from https://fish.audio/app/api-keys
4. OK out of all dialogs. **Restart** the terminal (and this app) so the variable is visible.
Session-only (PowerShell, not permanent):
```powershell
$env:FISH_AUDIO_API_KEY = "your_key_here"
```
## Run
**Desktop** (Notepad and other unelevated apps):
```powershell
python elo_stt_passive.py
```
**In some fullscreen games**, Windows hides keyboard state from other programs. If Right Ctrl does nothing while the game is focused, start elevated (optional):
```powershell
python elo_stt_passive.py --elevate
```
| Action | Result |
|--------|--------|
| Hold **Right Ctrl** | Record (includes buffer before the press) |
| Release **Right Ctrl** | Transcribe → type into the focused app |
| **Right Shift** while holding Right Ctrl | Cancel; soft cancel sound |
| **Ctrl+C** in the console | Quit |
## Configuration
Edit `config.ini` in this folder and save. Most settings — including **capture mode** — apply immediately; you do not need to restart the program. A fully commented template is in `config.example.ini`. Defaults and limits are also documented in the header of `elo_stt_passive.py`.
Useful keys:
- `[audio] capture_mode` — `microphone` (default), `system` (what you hear), or `both` (switch live)
- `[recording] buffer_seconds` — pre/post roll (default `0.5`)
- `[audio_processing] speech_boost_percent` — default `30` (×1.30 ≈ **+2.28 dB**)
- `[keystrokes] inter_key_delay` / `key_hold_duration`
- `[stt] timeout_seconds` — default `8`
- `[speech_detection] *` — ambient / speech gate
## MCP server
Start capture **and** expose tools to MCP clients:
```powershell
python elo_stt_passive.py --mcp
```
### Claude Desktop (example)
Add to your Claude Desktop MCP config (path may vary):
```json
{
"mcpServers": {
"elo-stt-passive": {
"command": "C:\\Projects\\Elo STT Passive\\repo\\.venv\\Scripts\\python.exe",
"args": [
"C:\\Projects\\Elo STT Passive\\repo\\elo_stt_passive.py",
"--mcp",
"--skip-api-key-check"
]
}
}
}
```
Set `FISH_AUDIO_API_KEY` in your user environment rather than putting it in the JSON file.
### Tools
| Tool | Purpose |
|------|---------|
| `get_recent_stt_results` | Last N transcripts |
| `get_latest_stt_result` | Single newest result |
| `get_stt_results_past_seconds` | Everything in the last N seconds |
| `get_stt_results_in_range` | Overlap with Unix timestamp range |
| `get_stt_results_since_iso` | Since an ISO-8601 time |
| `search_stt_results` | Substring search |
| `get_stt_result_by_id` | Lookup by id |
| `get_stt_stats` / `get_elo_stt_status` | Counts and runtime status |
| `clear_stt_history` | Wipe in-memory history |
Each success record includes **`hold_start_utc` / `hold_end_utc`** (and Unix equivalents) with millisecond precision, plus the transcript text.
Optional SSE transport for a long-running windowed app:
```powershell
python elo_stt_passive.py --mcp-sse
```
## Tests
```powershell
python -m pytest tests -q
```
## Project layout
```
elo_stt_passive.py # Entry point + documented defaults
config.ini # Your settings
config.example.ini # Template
elo_stt/ # Modular package
tests/
```
## Privacy & security
- The Fish Audio API key is read from the environment **only when needed**.
- This program **does not** write API keys to `config.ini` or any other file.
- Audio is sent to Fish Audio over HTTPS for transcription; review their terms for data handling.
- STT history is **in-memory only** (lost when the process exits), sized by `mcp.max_history`.
## License
MIT. See LICENSE. Fish Audio, Claude, and other trademarks belong to their respective owners.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues